embulk-output-bigquery 0.2.3 → 0.3.0.pre1

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.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +6 -12
  3. data/CHANGELOG.md +18 -0
  4. data/Gemfile +8 -0
  5. data/LICENSE.txt +20 -0
  6. data/README.md +165 -39
  7. data/Rakefile +11 -0
  8. data/embulk-output-bigquery.gemspec +20 -0
  9. data/example/config_client_options.yml +33 -0
  10. data/example/config_csv.yml +30 -0
  11. data/example/config_delete_in_advance.yml +29 -0
  12. data/example/config_expose_errors.yml +30 -0
  13. data/example/config_guess_from_embulk_schema.yml +29 -0
  14. data/example/config_guess_with_column_options.yml +40 -0
  15. data/example/config_gzip.yml +30 -0
  16. data/example/config_jsonl.yml +30 -0
  17. data/example/config_mode_append.yml +30 -0
  18. data/example/config_mode_append_direct.yml +30 -0
  19. data/example/config_payload_column.yml +20 -0
  20. data/example/config_payload_column_index.yml +20 -0
  21. data/example/config_prevent_duplicate_insert.yml +30 -0
  22. data/example/config_replace.yml +30 -0
  23. data/example/config_replace_backup.yml +32 -0
  24. data/example/config_skip_file_generation.yml +32 -0
  25. data/example/config_table_strftime.yml +30 -0
  26. data/example/config_template_table.yml +21 -0
  27. data/example/config_uncompressed.yml +30 -0
  28. data/example/config_with_rehearsal.yml +32 -0
  29. data/example/example.csv +17 -0
  30. data/example/example.jsonl +16 -0
  31. data/example/example.yml +30 -0
  32. data/example/json_key.json +12 -0
  33. data/example/nested_example.jsonl +16 -0
  34. data/example/schema.json +30 -0
  35. data/example/schema_expose_errors.json +30 -0
  36. data/lib/embulk/output/bigquery.rb +388 -3
  37. data/lib/embulk/output/bigquery/bigquery_client.rb +396 -0
  38. data/lib/embulk/output/bigquery/file_writer.rb +103 -0
  39. data/lib/embulk/output/bigquery/helper.rb +78 -0
  40. data/lib/embulk/output/bigquery/value_converter_factory.rb +292 -0
  41. data/test/helper.rb +13 -0
  42. data/test/test_bigquery_client.rb +166 -0
  43. data/test/test_configure.rb +254 -0
  44. data/test/test_example.rb +34 -0
  45. data/test/test_file_writer.rb +129 -0
  46. data/test/test_helper.rb +103 -0
  47. data/test/test_transaction.rb +129 -0
  48. data/test/test_value_converter_factory.rb +316 -0
  49. metadata +114 -45
  50. data/build.gradle +0 -80
  51. data/config/checkstyle/checkstyle.xml +0 -128
  52. data/config/checkstyle/default.xml +0 -108
  53. data/gradle/wrapper/gradle-wrapper.jar +0 -0
  54. data/gradle/wrapper/gradle-wrapper.properties +0 -6
  55. data/gradlew +0 -164
  56. data/gradlew.bat +0 -90
  57. data/settings.gradle +0 -2
  58. data/src/main/java/org/embulk/output/BigqueryAuthentication.java +0 -117
  59. data/src/main/java/org/embulk/output/BigqueryOutputPlugin.java +0 -508
  60. data/src/main/java/org/embulk/output/BigqueryWriter.java +0 -575
  61. data/src/test/java/org/embulk/output/TestBigqueryAuthentication.java +0 -5
  62. data/src/test/java/org/embulk/output/TestBigqueryOutputPlugin.java +0 -5
  63. data/src/test/java/org/embulk/output/TestBigqueryWriter.java +0 -5
@@ -0,0 +1,254 @@
1
+ require_relative './helper'
2
+ require 'embulk/output/bigquery'
3
+
4
+ Bigquery = Embulk::Output::Bigquery unless defined?(Bigquery)
5
+
6
+ module Embulk
7
+ class Output::Bigquery
8
+ class TestConfigure < Test::Unit::TestCase
9
+ class << self
10
+ def startup
11
+ FileUtils.mkdir_p('tmp')
12
+ end
13
+
14
+ def shutdown
15
+ FileUtils.rm_rf('tmp')
16
+ end
17
+ end
18
+
19
+ def least_config
20
+ DataSource.new({
21
+ 'project' => 'your_project_name',
22
+ 'dataset' => 'your_dataset_name',
23
+ 'table' => 'your_table_name',
24
+ 'p12_keyfile' => __FILE__, # fake
25
+ })
26
+ end
27
+
28
+ def schema
29
+ Schema.new([
30
+ Column.new({index: 0, name: 'boolean', type: :boolean}),
31
+ Column.new({index: 1, name: 'long', type: :long}),
32
+ Column.new({index: 2, name: 'double', type: :double}),
33
+ Column.new({index: 3, name: 'string', type: :string}),
34
+ Column.new({index: 4, name: 'timestamp', type: :timestamp}),
35
+ Column.new({index: 5, name: 'json', type: :json}),
36
+ ])
37
+ end
38
+
39
+ def processor_count
40
+ 1
41
+ end
42
+
43
+ def test_configure_default
44
+ task = Bigquery.configure(least_config, schema, processor_count)
45
+ assert_equal "append", task['mode']
46
+ assert_equal "private_key", task['auth_method']
47
+ assert_equal nil, task['service_account_email']
48
+ assert_equal __FILE__, task['p12_keyfile']
49
+ assert_equal nil, task['json_keyfile']
50
+ assert_equal "your_project_name", task['project']
51
+ assert_equal "your_dataset_name", task['dataset']
52
+ assert_equal "your_table_name", task['table']
53
+ assert_equal nil, task['dataset_old']
54
+ assert_equal nil, task['table_old']
55
+ assert_equal nil, task['table_name_old']
56
+ assert_equal false, task['auto_create_dataset']
57
+ assert_equal false, task['auto_create_table']
58
+ assert_equal nil, task['schema_file']
59
+ assert_equal nil, task['template_table']
60
+ assert_equal true, task['delete_from_local_when_job_end']
61
+ assert_equal 3600, task['job_status_max_polling_time']
62
+ assert_equal 10, task['job_status_polling_interval']
63
+ assert_equal false, task['is_skip_job_result_check']
64
+ assert_equal false, task['prevent_duplicate_insert']
65
+ assert_equal false, task['with_rehearsal']
66
+ assert_equal 1000, task['rehearsal_counts']
67
+ assert_equal [], task['column_options']
68
+ assert_equal "UTC", task['default_timezone']
69
+ assert_equal "%Y-%m-%d %H:%M:%S.%6N", task['default_timestamp_format']
70
+ assert_equal nil, task['payload_column']
71
+ assert_equal nil, task['payload_column_index']
72
+ assert_equal 300, task['timeout_sec']
73
+ assert_equal 300, task['open_timeout_sec']
74
+ assert_equal 5, task['retries']
75
+ assert_equal "Embulk BigQuery plugin", task['application_name']
76
+ # assert_equal "/tmp/embulk_output_bigquery_20160228-27184-pubcn0", task['path_prefix']
77
+ assert_equal ".%d.%03d", task['sequence_format']
78
+ assert_equal ".csv", task['file_ext']
79
+ assert_equal false, task['skip_file_generation']
80
+ assert_equal "NONE", task['compression']
81
+ assert_equal "CSV", task['source_format']
82
+ assert_equal 0, task['max_bad_records']
83
+ assert_equal ",", task['field_delimiter']
84
+ assert_equal "UTF-8", task['encoding']
85
+ assert_equal false, task['ignore_unknown_values']
86
+ assert_equal false, task['allow_quoted_newlines']
87
+ assert_equal false, task['skip_load']
88
+ end
89
+
90
+ def test_mode
91
+ config = least_config.merge('mode' => 'foobar')
92
+ assert_raise { Bigquery.configure(config, schema, processor_count) }
93
+
94
+ config = least_config.merge('mode' => 'append')
95
+ assert_nothing_raised { Bigquery.configure(config, schema, processor_count) }
96
+
97
+ config = least_config.merge('mode' => 'replace')
98
+ assert_nothing_raised { Bigquery.configure(config, schema, processor_count) }
99
+
100
+ config = least_config.merge('mode' => 'delete_in_advance')
101
+ assert_nothing_raised { Bigquery.configure(config, schema, processor_count) }
102
+
103
+ config = least_config.merge('mode' => 'replace_backup')
104
+ assert_raise { Bigquery.configure(config, schema, processor_count) }
105
+ end
106
+
107
+ def test_dataset_table_old
108
+ task = nil
109
+ config = least_config.merge('mode' => 'replace_backup', 'table_old' => 'backup')
110
+ assert_nothing_raised { task = Bigquery.configure(config, schema, processor_count) }
111
+ assert_equal task['dataset_old'], task['dataset']
112
+ assert_equal task['table_old'], 'backup'
113
+
114
+ config = least_config.merge('mode' => 'replace_backup', 'dataset_old' => 'backup')
115
+ assert_nothing_raised { task = Bigquery.configure(config, schema, processor_count) }
116
+ assert_equal task['dataset_old'], 'backup'
117
+ assert_equal task['table_old'], task['table']
118
+ end
119
+
120
+ def test_auth_method
121
+ config = least_config.merge('auth_method' => 'foobar')
122
+ assert_raise { Bigquery.configure(config, schema, processor_count) }
123
+
124
+ config = least_config.merge('auth_method' => 'private_key').tap {|h| h.delete('p12_keyfile') }
125
+ assert_raise { Bigquery.configure(config, schema, processor_count) }
126
+ config = least_config.merge('auth_method' => 'private_key', 'p12_keyfile' => 'dummy')
127
+ assert_nothing_raised { Bigquery.configure(config, schema, processor_count) }
128
+
129
+ config = least_config.merge('auth_method' => 'json_key').tap {|h| h.delete('json_keyfile') }
130
+ assert_raise { Bigquery.configure(config, schema, processor_count) }
131
+ config = least_config.merge('auth_method' => 'json_key', 'json_keyfile' => "#{EXAMPLE_ROOT}/json_key.json")
132
+ assert_nothing_raised { Bigquery.configure(config, schema, processor_count) }
133
+
134
+ config = least_config.merge('auth_method' => 'compute_engine')
135
+ assert_nothing_raised { Bigquery.configure(config, schema, processor_count) }
136
+ end
137
+
138
+ def test_json_keyfile
139
+ json_keyfile = "#{EXAMPLE_ROOT}/json_key.json"
140
+ config = least_config.merge('auth_method' => 'json_key', 'json_keyfile' => json_keyfile).tap {|h| h.delete('project') }
141
+ task = Bigquery.configure(config, schema, processor_count)
142
+ assert_not_equal nil, task['project'] # project is obtained from json_keyfile if available
143
+
144
+ config = least_config.merge('auth_method' => 'json_key', 'json_keyfile' => { 'content' => File.read(json_keyfile) }).tap {|h| h.delete('project') }
145
+ task = Bigquery.configure(config, schema, processor_count)
146
+ assert_not_equal nil, task['project'] # project is obtained from json_keyfile if available
147
+
148
+ config = least_config.merge('auth_method' => 'json_key', 'json_keyfile' => { 'content' => 'not a json' })
149
+ assert_raise { Bigquery.configure(config, schema, processor_count) }
150
+ end
151
+
152
+ def test_payload_column
153
+ config = least_config.merge('payload_column' => schema.first.name)
154
+ task = Bigquery.configure(config, schema, processor_count)
155
+ assert_equal task['payload_column_index'], 0
156
+
157
+ config = least_config.merge('payload_column' => 'not_exist')
158
+ assert_raise { Bigquery.configure(config, schema, processor_count) }
159
+ end
160
+
161
+ def test_payload_column_index
162
+ config = least_config.merge('payload_column_index' => 0)
163
+ assert_nothing_raised { Bigquery.configure(config, schema, processor_count) }
164
+
165
+ config = least_config.merge('payload_column_index' => -1)
166
+ assert_raise { Bigquery.configure(config, schema, processor_count) }
167
+
168
+ config = least_config.merge('payload_column_index' => schema.size)
169
+ assert_raise { Bigquery.configure(config, schema, processor_count) }
170
+ end
171
+
172
+ def test_auto_create_table_with_payload_column
173
+ config = least_config.merge('auto_create_table' => true, 'payload_column' => 'json')
174
+ assert_raise { Bigquery.configure(config, schema, processor_count) }
175
+
176
+ config = least_config.merge('auto_create_table' => true, 'payload_column' => 'json', 'schema_file' => "#{EXAMPLE_ROOT}/schema.json")
177
+ assert_nothing_raised { Bigquery.configure(config, schema, processor_count) }
178
+
179
+ config = least_config.merge('auto_create_table' => true, 'payload_column' => 'json', 'template_table' => 'foo')
180
+ assert_nothing_raised { Bigquery.configure(config, schema, processor_count) }
181
+ end
182
+
183
+ def test_auto_create_table_with_payload_column_index
184
+ config = least_config.merge('auto_create_table' => true, 'payload_column_index' => 0)
185
+ assert_raise { Bigquery.configure(config, schema, processor_count) }
186
+
187
+ config = least_config.merge('auto_create_table' => true, 'payload_column_index' => 0, 'schema_file' => "#{EXAMPLE_ROOT}/schema.json")
188
+ assert_nothing_raised { Bigquery.configure(config, schema, processor_count) }
189
+
190
+ config = least_config.merge('auto_create_table' => true, 'payload_column_index' => 0, 'template_table' => 'foo')
191
+ assert_nothing_raised { Bigquery.configure(config, schema, processor_count) }
192
+ end
193
+
194
+ def test_schema_file
195
+ config = least_config.merge('schema_file' => "#{EXAMPLE_ROOT}/schema.json")
196
+ assert_nothing_raised { Bigquery.configure(config, schema, processor_count) }
197
+
198
+ config = least_config.merge('schema_file' => "not_found.json")
199
+ assert_raise { Bigquery.configure(config, schema, processor_count) }
200
+
201
+ File.write("tmp/bad_schema.json", "not_a_json")
202
+ config = least_config.merge('schema_file' => "tmp/bad_schema.json")
203
+ assert_raise { Bigquery.configure(config, schema, processor_count) }
204
+ end
205
+
206
+ def test_source_format
207
+ config = least_config.merge('source_format' => 'csv')
208
+ assert_nothing_raised { Bigquery.configure(config, schema, processor_count) }
209
+
210
+ config = least_config.merge('source_format' => 'jsonl')
211
+ assert_nothing_raised { Bigquery.configure(config, schema, processor_count) }
212
+
213
+ config = least_config.merge('source_format' => 'newline_delimited_json')
214
+ assert_nothing_raised { Bigquery.configure(config, schema, processor_count) }
215
+
216
+ config = least_config.merge('source_format' => 'foobar')
217
+ assert_raise { Bigquery.configure(config, schema, processor_count) }
218
+ end
219
+
220
+ def test_compression
221
+ config = least_config.merge('compression' => 'gzip')
222
+ assert_nothing_raised { Bigquery.configure(config, schema, processor_count) }
223
+
224
+ config = least_config.merge('compression' => 'none')
225
+ assert_nothing_raised { Bigquery.configure(config, schema, processor_count) }
226
+
227
+ config = least_config.merge('compression' => 'foobar')
228
+ assert_raise { Bigquery.configure(config, schema, processor_count) }
229
+ end
230
+
231
+ def test_file_ext
232
+ config = least_config.merge('source_format' => 'csv', 'compression' => 'gzip')
233
+ task = Bigquery.configure(config, schema, processor_count)
234
+ assert_equal '.csv.gz', task['file_ext']
235
+
236
+ config = least_config.merge('source_format' => 'NEWLINE_DELIMITED_JSON', 'compression' => 'gzip')
237
+ task = Bigquery.configure(config, schema, processor_count)
238
+ assert_equal '.jsonl.gz', task['file_ext']
239
+
240
+ config = least_config.merge('source_format' => 'csv', 'compression' => 'none')
241
+ task = Bigquery.configure(config, schema, processor_count)
242
+ assert_equal '.csv', task['file_ext']
243
+
244
+ config = least_config.merge('source_format' => 'NEWLINE_DELIMITED_JSON', 'compression' => 'none')
245
+ task = Bigquery.configure(config, schema, processor_count)
246
+ assert_equal '.jsonl', task['file_ext']
247
+
248
+ config = least_config.merge('file_ext' => '.foo')
249
+ task = Bigquery.configure(config, schema, processor_count)
250
+ assert_equal '.foo', task['file_ext']
251
+ end
252
+ end
253
+ end
254
+ end
@@ -0,0 +1,34 @@
1
+ require_relative './helper'
2
+
3
+ # 1. Prepare /tmp/your-project-000.json
4
+ # 2. embulk bundle
5
+ # 3. CONNECT=1 bundle exec ruby test/test_example.rb
6
+
7
+ if ENV['CONNECT']
8
+ class TestExample < Test::Unit::TestCase
9
+ def embulk_path
10
+ if File.exist?("#{ENV['PATH']}/.embulk/bin/embulk")
11
+ "#{ENV['PATH']}/.embulk/bin/embulk"
12
+ elsif File.exist?("/usr/local/bin/embulk")
13
+ "/usr/local/bin/embulk"
14
+ else
15
+ "embulk"
16
+ end
17
+ end
18
+
19
+ files = Dir.glob("#{APP_ROOT}/example/config_*.yml").sort
20
+ files = files.reject {|file| File.symlink?(file) }
21
+ # files.shift
22
+ files.each do |config_path|
23
+ define_method(:"test_#{File.basename(config_path, ".yml")}") do
24
+ success = Bundler.with_clean_env do
25
+ cmd = "#{embulk_path} run -X page_size=1 -b . -l trace #{config_path}"
26
+ puts "=" * 64
27
+ puts cmd
28
+ system(cmd)
29
+ end
30
+ assert_true success
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,129 @@
1
+ require_relative './helper'
2
+ require 'embulk/output/bigquery/file_writer'
3
+ require 'fileutils'
4
+ require 'zlib'
5
+
6
+ module Embulk
7
+ class Output::Bigquery
8
+ class TestFileWriter < Test::Unit::TestCase
9
+ class << self
10
+ def startup
11
+ FileUtils.mkdir_p('tmp')
12
+ end
13
+
14
+ def shutdown
15
+ FileUtils.rm_rf('tmp')
16
+ end
17
+ end
18
+
19
+ def default_task
20
+ {
21
+ 'compression' => 'GZIP',
22
+ 'payload_column' => nil,
23
+ 'source_format' => 'CSV',
24
+ 'path_prefix' => 'tmp/path_prefix',
25
+ 'sequence_format' => '.%d.%03d',
26
+ 'file_ext' => nil,
27
+ }
28
+ end
29
+
30
+ def schema
31
+ Schema.new([
32
+ Column.new({index: 0, name: 'boolean', type: :boolean}),
33
+ Column.new({index: 1, name: 'long', type: :long}),
34
+ Column.new({index: 2, name: 'double', type: :double}),
35
+ Column.new({index: 3, name: 'string', type: :string}),
36
+ Column.new({index: 4, name: 'timestamp', type: :timestamp}),
37
+ Column.new({index: 5, name: 'json', type: :json}),
38
+ ])
39
+ end
40
+
41
+ def converters
42
+ @converters ||= ValueConverterFactory.create_converters(default_task, schema)
43
+ end
44
+
45
+ sub_test_case "path" do
46
+ def test_path
47
+ task = default_task.merge('path_prefix' => 'tmp/foo', 'sequence_format' => '', 'file_ext' => '.1')
48
+ file_writer = FileWriter.new(task, schema, 0, converters)
49
+ assert_equal 'tmp/foo.1', file_writer.instance_variable_get(:@path)
50
+ end
51
+ end
52
+
53
+ sub_test_case "formatter" do
54
+ def record
55
+ [true, 1, 1.1, 'foo', Time.parse("2016-02-26 00:00:00 +09:00"), {"foo"=>"foo"}]
56
+ end
57
+
58
+ def test_payload_column_index
59
+ task = default_task.merge('payload_column_index' => 0)
60
+ file_writer = FileWriter.new(task, schema, 0, converters)
61
+ formatter_proc = file_writer.instance_variable_get(:@formatter_proc)
62
+ assert_equal :to_payload, formatter_proc.name
63
+
64
+ assert_equal %Q[true\n], formatter_proc.call(record)
65
+ end
66
+
67
+ def test_csv
68
+ task = default_task.merge('source_format' => 'CSV')
69
+ file_writer = FileWriter.new(task, schema, 0, converters)
70
+ formatter_proc = file_writer.instance_variable_get(:@formatter_proc)
71
+ assert_equal :to_csv, formatter_proc.name
72
+
73
+ expected = %Q[true,1,1.1,foo,1456412400.0,"{""foo"":""foo""}"\n]
74
+ assert_equal expected, formatter_proc.call(record)
75
+ end
76
+
77
+ def test_jsonl
78
+ task = default_task.merge('source_format' => 'NEWLINE_DELIMITED_JSON')
79
+ file_writer = FileWriter.new(task, schema, 0, converters)
80
+ formatter_proc = file_writer.instance_variable_get(:@formatter_proc)
81
+ assert_equal :to_jsonl, formatter_proc.name
82
+
83
+ expected = %Q[{"boolean":true,"long":1,"double":1.1,"string":"foo","timestamp":1456412400.0,"json":"{\\"foo\\":\\"foo\\"}"}\n]
84
+ assert_equal expected, formatter_proc.call(record)
85
+ end
86
+ end
87
+
88
+ sub_test_case "compression" do
89
+ def record
90
+ [true, 1, 1.1, 'foo', Time.parse("2016-02-26 00:00:00 +09:00"), {"foo"=>"foo"}]
91
+ end
92
+
93
+ def page
94
+ [record]
95
+ end
96
+
97
+ def test_gzip
98
+ task = default_task.merge('compression' => 'GZIP')
99
+ file_writer = FileWriter.new(task, schema, 0, converters)
100
+ io = file_writer.instance_variable_get(:@io)
101
+ assert_equal Zlib::GzipWriter, io.class
102
+
103
+ begin
104
+ file_writer.add(page)
105
+ ensure
106
+ file_writer.commit
107
+ end
108
+ assert_true File.exist?(file_writer.path)
109
+ assert_nothing_raised { Zlib::GzipReader.open(file_writer.path) {|gz| } }
110
+ end
111
+
112
+ def test_uncompressed
113
+ task = default_task.merge('compression' => 'NONE')
114
+ file_writer = FileWriter.new(task, schema, 0, converters)
115
+ io = file_writer.instance_variable_get(:@io)
116
+ assert_equal File, io.class
117
+
118
+ begin
119
+ file_writer.add(page)
120
+ ensure
121
+ file_writer.commit
122
+ end
123
+ assert_true File.exist?(file_writer.path)
124
+ assert_raise { Zlib::GzipReader.open(file_writer.path) {|gz| } }
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,103 @@
1
+ require_relative './helper'
2
+ require 'embulk/output/bigquery/helper'
3
+
4
+ module Embulk
5
+ class Output::Bigquery
6
+ class TestHelper < Test::Unit::TestCase
7
+ class << self
8
+ def startup
9
+ FileUtils.mkdir_p('tmp')
10
+ end
11
+
12
+ def shutdown
13
+ FileUtils.rm_rf('tmp')
14
+ end
15
+ end
16
+
17
+ def bq_type_from_embulk_type
18
+ assert_equal 'BOOLEAN', Helper.bq_type_from_embulk_type(:boolean)
19
+ assert_equal 'STRING', Helper.bq_type_from_embulk_type(:string)
20
+ assert_equal 'FLOAT', Helper.bq_type_from_embulk_type(:double)
21
+ assert_equal 'STRING', Helper.bq_type_from_embulk_type(:string)
22
+ assert_equal 'TIMESTAMP', Helper.bq_type_from_embulk_type(:timestamp)
23
+ assert_equal 'STRING', Helper.bq_type_from_embulk_type(:json)
24
+ end
25
+
26
+ sub_test_case "fields_from_embulk_schema" do
27
+ def test_fields_from_embulk_schema_without_column_options
28
+ schema = Schema.new([
29
+ Column.new({index: 0, name: 'boolean', type: :boolean}),
30
+ Column.new({index: 1, name: 'long', type: :long}),
31
+ Column.new({index: 2, name: 'double', type: :double}),
32
+ Column.new({index: 3, name: 'string', type: :string}),
33
+ Column.new({index: 4, name: 'timestamp', type: :timestamp}),
34
+ Column.new({index: 5, name: 'json', type: :json}),
35
+ ])
36
+ expected = [
37
+ {name: 'boolean', type: 'BOOLEAN'},
38
+ {name: 'long', type: 'INTEGER'},
39
+ {name: 'double', type: 'FLOAT'},
40
+ {name: 'string', type: 'STRING'},
41
+ {name: 'timestamp', type: 'TIMESTAMP'},
42
+ {name: 'json', type: 'STRING'},
43
+ ]
44
+ fields = Helper.fields_from_embulk_schema({}, schema)
45
+ assert_equal expected, fields
46
+ end
47
+
48
+ def test_fields_from_embulk_schema_with_column_options
49
+ schema = Schema.new([
50
+ Column.new({index: 0, name: 'boolean', type: :boolean}),
51
+ Column.new({index: 1, name: 'long', type: :long}),
52
+ Column.new({index: 2, name: 'double', type: :double}),
53
+ Column.new({index: 3, name: 'string', type: :string}),
54
+ Column.new({index: 4, name: 'timestamp', type: :timestamp}),
55
+ Column.new({index: 5, name: 'json', type: :json}),
56
+ ])
57
+ task = {
58
+ 'column_options' => [
59
+ {'name' => 'boolean', 'type' => 'STRING', 'mode' => 'REQUIRED'},
60
+ {'name' => 'long', 'type' => 'STRING'},
61
+ {'name' => 'double', 'type' => 'STRING'},
62
+ {'name' => 'string', 'type' => 'INTEGER'},
63
+ {'name' => 'timestamp', 'type' => 'INTEGER'},
64
+ {'name' => 'json', 'type' => 'RECORD', 'fields' => [
65
+ { 'name' => 'key1', 'type' => 'STRING' },
66
+ ]},
67
+ ],
68
+ }
69
+ expected = [
70
+ {name: 'boolean', type: 'STRING', mode: 'REQUIRED'},
71
+ {name: 'long', type: 'STRING'},
72
+ {name: 'double', type: 'STRING'},
73
+ {name: 'string', type: 'INTEGER'},
74
+ {name: 'timestamp', type: 'INTEGER'},
75
+ {name: 'json', type: 'RECORD', fields: [
76
+ {name: 'key1', type: 'STRING'},
77
+ ]},
78
+ ]
79
+ fields = Helper.fields_from_embulk_schema(task, schema)
80
+ assert_equal expected, fields
81
+ end
82
+ end
83
+
84
+ def test_create_job_id
85
+ task = {
86
+ 'dataset' => 'your_dataset_name',
87
+ 'source_format' => 'CSV',
88
+ 'max_bad_records' => nil,
89
+ 'field_delimiter' => ',',
90
+ 'encoding' => 'UTF-8',
91
+ 'ignore_unknown_values' => nil,
92
+ 'allow_quoted_newlines' => nil,
93
+ }
94
+ fields = {
95
+ name: 'a', type: 'STRING',
96
+ }
97
+ File.write("tmp/your_file_name", "foobarbaz")
98
+ job_id = Helper.create_job_id(task, 'tmp/your_file_name', 'your_table_name', fields)
99
+ assert job_id.is_a?(String)
100
+ end
101
+ end
102
+ end
103
+ end