embulk-input-jira 0.2.5 → 0.2.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +10 -5
- data/.travis.yml +4 -34
- data/CHANGELOG.md +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +5 -4
- data/build.gradle +116 -0
- data/config/checkstyle/checkstyle.xml +128 -0
- data/config/checkstyle/default.xml +108 -0
- data/gradle/wrapper/gradle-wrapper.jar +0 -0
- data/gradle/wrapper/gradle-wrapper.properties +5 -0
- data/gradlew +172 -0
- data/gradlew.bat +84 -0
- data/lib/embulk/guess/jira.rb +24 -0
- data/lib/embulk/input/jira.rb +3 -169
- data/src/main/java/org/embulk/input/jira/AuthenticateMethod.java +27 -0
- data/src/main/java/org/embulk/input/jira/Constant.java +17 -0
- data/src/main/java/org/embulk/input/jira/Issue.java +150 -0
- data/src/main/java/org/embulk/input/jira/JiraInputPlugin.java +226 -0
- data/src/main/java/org/embulk/input/jira/client/JiraClient.java +254 -0
- data/src/main/java/org/embulk/input/jira/util/JiraException.java +18 -0
- data/src/main/java/org/embulk/input/jira/util/JiraUtil.java +264 -0
- data/src/test/java/org/embulk/input/jira/IssueTest.java +278 -0
- data/src/test/java/org/embulk/input/jira/JiraInputPluginTest.java +204 -0
- data/src/test/java/org/embulk/input/jira/JiraPluginTestRuntime.java +133 -0
- data/src/test/java/org/embulk/input/jira/TestHelpers.java +41 -0
- data/src/test/java/org/embulk/input/jira/client/JiraClientTest.java +222 -0
- data/src/test/java/org/embulk/input/jira/util/JiraUtilTest.java +318 -0
- data/src/test/resources/config.yml +13 -0
- data/src/test/resources/issue_flatten.json +129 -0
- data/src/test/resources/issue_flatten_expected.json +73 -0
- data/src/test/resources/issue_get.json +36 -0
- data/src/test/resources/issue_get_expected.json +62 -0
- data/src/test/resources/jira_client.json +81 -0
- data/src/test/resources/jira_input_plugin.json +114 -0
- data/src/test/resources/jira_util.json +26 -0
- metadata +55 -175
- data/Gemfile +0 -3
- data/LICENSE +0 -13
- data/Rakefile +0 -15
- data/embulk-input-jira.gemspec +0 -27
- data/gemfiles/embulk-0.8.0-latest +0 -4
- data/gemfiles/embulk-0.8.7 +0 -4
- data/gemfiles/embulk-0.8.8 +0 -4
- data/gemfiles/embulk-latest +0 -4
- data/gemfiles/template.erb +0 -4
- data/lib/embulk/input/jira_api.rb +0 -9
- data/lib/embulk/input/jira_api/client.rb +0 -144
- data/lib/embulk/input/jira_api/issue.rb +0 -133
- data/lib/embulk/input/jira_input_plugin_utils.rb +0 -58
- data/spec/embulk/input/jira-input-plugin-utils_spec.rb +0 -89
- data/spec/embulk/input/jira_api/client_spec.rb +0 -224
- data/spec/embulk/input/jira_api/issue_spec.rb +0 -394
- data/spec/embulk/input/jira_spec.rb +0 -322
- data/spec/embulk_spec.rb +0 -32
- data/spec/spec_helper.rb +0 -26
- data/spec/support/stdout_and_err_capture.rb +0 -45
data/Gemfile
DELETED
data/LICENSE
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
Copyright 2015 Everyleaf Corporation
|
2
|
-
|
3
|
-
Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
-
you may not use this file except in compliance with the License.
|
5
|
-
You may obtain a copy of the License at
|
6
|
-
|
7
|
-
http://www.apache.org/licenses/LICENSE-2.0
|
8
|
-
|
9
|
-
Unless required by applicable law or agreed to in writing, software
|
10
|
-
distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
-
See the License for the specific language governing permissions and
|
13
|
-
limitations under the License.
|
data/Rakefile
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
require "bundler/gem_tasks"
|
2
|
-
require 'rspec/core/rake_task'
|
3
|
-
require "everyleaf/embulk_helper/tasks"
|
4
|
-
|
5
|
-
Everyleaf::EmbulkHelper::Tasks.install({
|
6
|
-
gemspec: "./embulk-input-jira.gemspec",
|
7
|
-
github_name: "treasure-data/embulk-input-jira",
|
8
|
-
})
|
9
|
-
|
10
|
-
task default: :spec
|
11
|
-
|
12
|
-
desc "Run all examples"
|
13
|
-
RSpec::Core::RakeTask.new(:spec) do |t|
|
14
|
-
t.rspec_opts = %w[--color]
|
15
|
-
end
|
data/embulk-input-jira.gemspec
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
Gem::Specification.new do |spec|
|
2
|
-
spec.name = "embulk-input-jira"
|
3
|
-
spec.version = "0.2.5"
|
4
|
-
spec.authors = ["uu59", "yoshihara"]
|
5
|
-
spec.summary = "Jira input plugin for Embulk"
|
6
|
-
spec.description = "Loads records from Jira."
|
7
|
-
spec.email = ["k@uu59.org", "h.yoshihara@everyleaf.com"]
|
8
|
-
spec.licenses = ["Apache2"]
|
9
|
-
spec.homepage = "https://github.com/treasure-data/embulk-input-jira"
|
10
|
-
|
11
|
-
spec.files = `git ls-files`.split("\n") + Dir["classpath/*.jar"]
|
12
|
-
spec.test_files = spec.files.grep(%r{^(test|spec)/})
|
13
|
-
spec.require_paths = ["lib"]
|
14
|
-
|
15
|
-
spec.add_dependency 'jiralicious', ['~> 0.5.0']
|
16
|
-
spec.add_dependency 'parallel', ['~> 1.6.0']
|
17
|
-
spec.add_dependency 'ruby-limiter', ['~> 1.0']
|
18
|
-
spec.add_dependency 'perfect_retry', ['~> 0.3']
|
19
|
-
spec.add_development_dependency 'bundler', ['~> 1.0']
|
20
|
-
spec.add_development_dependency 'rake', ['< 11.0']
|
21
|
-
spec.add_development_dependency 'rspec', "~> 3.2.0"
|
22
|
-
spec.add_development_dependency 'embulk', ["~> 0.8.7"]
|
23
|
-
spec.add_development_dependency 'simplecov'
|
24
|
-
spec.add_development_dependency 'pry'
|
25
|
-
spec.add_development_dependency 'codeclimate-test-reporter'
|
26
|
-
spec.add_development_dependency 'everyleaf-embulk_helper'
|
27
|
-
end
|
data/gemfiles/embulk-0.8.7
DELETED
data/gemfiles/embulk-0.8.8
DELETED
data/gemfiles/embulk-latest
DELETED
data/gemfiles/template.erb
DELETED
@@ -1,144 +0,0 @@
|
|
1
|
-
require "jiralicious"
|
2
|
-
require "parallel"
|
3
|
-
require "limiter"
|
4
|
-
require "embulk/input/jira_api/issue"
|
5
|
-
require "timeout"
|
6
|
-
|
7
|
-
module Embulk
|
8
|
-
module Input
|
9
|
-
module JiraApi
|
10
|
-
class Client
|
11
|
-
MAX_RATE_LIMIT = 50
|
12
|
-
MIN_RATE_LIMIT = 2
|
13
|
-
# Normal http request timeout is 300s
|
14
|
-
SEARCH_ISSUES_TIMEOUT_SECONDS = 300
|
15
|
-
DEFAULT_SEARCH_RETRY_TIMES = 10
|
16
|
-
|
17
|
-
def initialize
|
18
|
-
@rate_limiter = Limiter::RateQueue.new(MAX_RATE_LIMIT, interval: 2)
|
19
|
-
end
|
20
|
-
|
21
|
-
def self.setup(&block)
|
22
|
-
Jiralicious.configure(&block)
|
23
|
-
new
|
24
|
-
end
|
25
|
-
|
26
|
-
def search_issues(jql, options={})
|
27
|
-
issues_raw = search(jql, options).issues_raw
|
28
|
-
# Maximum number of issues to retrieve is 50
|
29
|
-
rate_limit = MAX_RATE_LIMIT
|
30
|
-
success_items = []
|
31
|
-
fail_items = []
|
32
|
-
error_object = nil
|
33
|
-
timeout_and_retry(SEARCH_ISSUES_TIMEOUT_SECONDS * MAX_RATE_LIMIT ) do
|
34
|
-
retry_count = 0
|
35
|
-
semaphore = Mutex.new
|
36
|
-
@rate_limiter = Limiter::RateQueue.new(rate_limit, interval: 2)
|
37
|
-
error_object = nil
|
38
|
-
while issues_raw.length > 0 && retry_count <= DEFAULT_SEARCH_RETRY_TIMES do
|
39
|
-
Parallel.each(issues_raw, in_threads: rate_limit) do |issue_raw|
|
40
|
-
# https://github.com/dorack/jiralicious/blob/v0.4.0/lib/jiralicious/search_result.rb#L32-34
|
41
|
-
begin
|
42
|
-
issue = find_issue(issue_raw["key"])
|
43
|
-
semaphore.synchronize {
|
44
|
-
success_items.push(JiraApi::Issue.new(issue))
|
45
|
-
}
|
46
|
-
rescue MultiJson::ParseError => e
|
47
|
-
html = e.message
|
48
|
-
title = html[%r|<title>(.*?)</title>|, 1]
|
49
|
-
# 401 due to high number of concurrent requests with current account
|
50
|
-
# The number of concurrent requests is not fixed by every account
|
51
|
-
# Hence catch the error item and retry later
|
52
|
-
raise title if title != "Unauthorized (401)"
|
53
|
-
semaphore.synchronize {
|
54
|
-
fail_items.push(issue_raw)
|
55
|
-
error_object = e
|
56
|
-
}
|
57
|
-
end
|
58
|
-
end
|
59
|
-
retry_count += 1
|
60
|
-
rate_limit = calculate_rate_limit(rate_limit, issues_raw.length, fail_items.length, retry_count)
|
61
|
-
issues_raw = fail_items
|
62
|
-
fail_items = []
|
63
|
-
raise error_object if retry_count > DEFAULT_SEARCH_RETRY_TIMES && !error_object.nil?
|
64
|
-
# Sleep after some seconds for JIRA API perhaps under the overload
|
65
|
-
sleep retry_count if fail_items.length > 0
|
66
|
-
end
|
67
|
-
success_items
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def search(jql, options={})
|
72
|
-
timeout_and_retry(SEARCH_ISSUES_TIMEOUT_SECONDS) do
|
73
|
-
Jiralicious.search(jql, options)
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
def total_count(jql)
|
78
|
-
search(jql, max_results: 1).num_results
|
79
|
-
end
|
80
|
-
|
81
|
-
def check_user_credential(username)
|
82
|
-
Jiralicious::User.search(username)
|
83
|
-
rescue Jiralicious::JqlError, Jiralicious::AuthenticationError, Jiralicious::NotLoggedIn, Jiralicious::InvalidLogin => e
|
84
|
-
raise Embulk::ConfigError.new(e.message)
|
85
|
-
rescue ::SocketError => e
|
86
|
-
# wrong `uri` option given
|
87
|
-
raise Embulk::ConfigError.new(e.message)
|
88
|
-
rescue MultiJson::ParseError => e
|
89
|
-
html = e.message
|
90
|
-
title = html[%r|<title>(.*?)</title>|, 1] #=> e.g. "Unauthorized (401)"
|
91
|
-
raise ConfigError.new("Can not authorize with your credential.") if title == 'Unauthorized (401)'
|
92
|
-
end
|
93
|
-
|
94
|
-
# Calculate rate limit based on previous run result
|
95
|
-
# Return 2 MIN_RATE_LIMIT in case turning from the 5th times or success_items is less than 2
|
96
|
-
# Otherwise return the min number between fail_items, success_items and current_limit
|
97
|
-
def calculate_rate_limit(current_limit, all_items, fail_items, times)
|
98
|
-
success_items = all_items - fail_items
|
99
|
-
return MIN_RATE_LIMIT if times >= DEFAULT_SEARCH_RETRY_TIMES/2 || success_items < MIN_RATE_LIMIT
|
100
|
-
return [fail_items, success_items, current_limit].min
|
101
|
-
end
|
102
|
-
|
103
|
-
private
|
104
|
-
|
105
|
-
def timeout_and_retry(wait, retry_times = DEFAULT_SEARCH_RETRY_TIMES, &block)
|
106
|
-
count = 0
|
107
|
-
begin
|
108
|
-
Timeout.timeout(wait) do
|
109
|
-
yield
|
110
|
-
end
|
111
|
-
rescue Jiralicious::JqlError, Jiralicious::AuthenticationError, Jiralicious::NotLoggedIn, Jiralicious::InvalidLogin => e
|
112
|
-
raise Embulk::ConfigError.new(e.message)
|
113
|
-
rescue ::SocketError => e
|
114
|
-
# wrong `uri` option given
|
115
|
-
raise Embulk::ConfigError.new(e.message)
|
116
|
-
rescue MultiJson::ParseError => e
|
117
|
-
# same as this Mailchimp plugin issue: https://github.com/treasure-data/embulk-output-mailchimp/issues/10
|
118
|
-
# (a) JIRA returns error as HTML, but HTTParty try to parse it as JSON.
|
119
|
-
# And (b) `search_issues` method has race-condition bug. If it occurred, MultiJson::ParseError raised too.
|
120
|
-
html = e.message
|
121
|
-
title = html[%r|<title>(.*?)</title>|, 1] #=> e.g. "Unauthorized (401)"
|
122
|
-
raise title if title == "Atlassian Cloud Notifications - Page Unavailable"
|
123
|
-
count += 1
|
124
|
-
raise title.nil? ? "Unknown Error" : title if count > retry_times
|
125
|
-
Embulk.logger.warn "JIRA returns error: #{title == 'Unauthorized (401)' ? title + " due to overloading API requests. Retrying on failed items only" : title}."
|
126
|
-
sleep count
|
127
|
-
retry
|
128
|
-
rescue Timeout::Error => e
|
129
|
-
count += 1
|
130
|
-
raise e if count > retry_times
|
131
|
-
Embulk.logger.warn "Time out error."
|
132
|
-
sleep count # retry after some seconds for JIRA API perhaps under the overload
|
133
|
-
retry
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
def find_issue(issue_key)
|
138
|
-
@rate_limiter.shift
|
139
|
-
Jiralicious::Issue.find(issue_key)
|
140
|
-
end
|
141
|
-
end
|
142
|
-
end
|
143
|
-
end
|
144
|
-
end
|
@@ -1,133 +0,0 @@
|
|
1
|
-
module Embulk
|
2
|
-
module Input
|
3
|
-
module JiraApi
|
4
|
-
class Issue
|
5
|
-
attr_reader :id, :key, :fields
|
6
|
-
|
7
|
-
def initialize(attributes)
|
8
|
-
@id = attributes.fetch("id")
|
9
|
-
|
10
|
-
# https://github.com/dorack/jiralicious/blob/404b7b6d5b7020f42064cf8d7a745ab02057e728/lib/jiralicious/issue.rb#L11-L12
|
11
|
-
@key = attributes.fetch("jira_key")
|
12
|
-
@fields = attributes.fetch("fields")
|
13
|
-
end
|
14
|
-
|
15
|
-
def [](attribute)
|
16
|
-
case attribute
|
17
|
-
when "id"
|
18
|
-
return id
|
19
|
-
when "key"
|
20
|
-
return key
|
21
|
-
end
|
22
|
-
|
23
|
-
attribute_keys = attribute.split('.')
|
24
|
-
|
25
|
-
fetch(fields, attribute_keys)
|
26
|
-
end
|
27
|
-
|
28
|
-
def to_record
|
29
|
-
@record = {}
|
30
|
-
|
31
|
-
@record["id"] = id
|
32
|
-
@record["key"] = key
|
33
|
-
|
34
|
-
generate_record(fields, "")
|
35
|
-
|
36
|
-
@record
|
37
|
-
end
|
38
|
-
|
39
|
-
private
|
40
|
-
|
41
|
-
def fetch(fields, keys)
|
42
|
-
return fields if fields.nil? || (fields.is_a?(Array) && fields.empty?)
|
43
|
-
|
44
|
-
if keys.empty?
|
45
|
-
case fields
|
46
|
-
when Array
|
47
|
-
values = fields.map do |field|
|
48
|
-
if field.is_a?(String)
|
49
|
-
field.to_s
|
50
|
-
else
|
51
|
-
field.to_json
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
return values.join(",")
|
56
|
-
when Hash
|
57
|
-
return fields.to_json
|
58
|
-
else
|
59
|
-
return fields
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
target_key = keys.shift
|
64
|
-
if fields.is_a?(Array)
|
65
|
-
values = fields.map do |field|
|
66
|
-
if field.is_a?(Hash)
|
67
|
-
field[target_key]
|
68
|
-
else
|
69
|
-
field.to_json
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
fetch(values, keys)
|
74
|
-
else
|
75
|
-
fetch(fields[target_key], keys)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
def generate_record(value, prefix_key)
|
80
|
-
case value
|
81
|
-
when Hash
|
82
|
-
# NOTE: If you want to flatten JSON completely, please
|
83
|
-
# remove this if...end and #add_heuristic_value.
|
84
|
-
if prefix_key.count(".") > 1
|
85
|
-
add_heuristic_value(value, prefix_key)
|
86
|
-
return
|
87
|
-
end
|
88
|
-
|
89
|
-
value.each_pair do |_key, _value|
|
90
|
-
generate_record(_value, record_key(prefix_key, _key))
|
91
|
-
end
|
92
|
-
when Array
|
93
|
-
if value.empty? || value.any? {|v| !v.is_a?(Hash) }
|
94
|
-
@record[prefix_key] = "\"#{value.map(&:to_s).join(',')}\""
|
95
|
-
return
|
96
|
-
end
|
97
|
-
|
98
|
-
# gathering values from each Hash
|
99
|
-
keys = value.map(&:keys).inject([]) {|sum, key| sum + key }.uniq
|
100
|
-
values = value.inject({}) do |sum, elem|
|
101
|
-
keys.each {|key| sum[key] = (sum[key] || []) << elem[key] }
|
102
|
-
sum
|
103
|
-
end
|
104
|
-
|
105
|
-
generate_record(values, prefix_key)
|
106
|
-
else
|
107
|
-
@record[prefix_key] = value
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
def record_key(prefix, key)
|
112
|
-
return key if prefix.empty?
|
113
|
-
|
114
|
-
"#{prefix}.#{key}"
|
115
|
-
end
|
116
|
-
|
117
|
-
def add_heuristic_value(hash, prefix_key)
|
118
|
-
heuristic_values = hash.select do |key, value|
|
119
|
-
["name", "key", "id"].include?(key) && !value.nil?
|
120
|
-
end
|
121
|
-
|
122
|
-
if heuristic_values.empty?
|
123
|
-
@record[prefix_key] = hash.to_json
|
124
|
-
else
|
125
|
-
heuristic_values.each do |key, value|
|
126
|
-
@record[record_key(prefix_key, key)] = value
|
127
|
-
end
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
@@ -1,58 +0,0 @@
|
|
1
|
-
# This module contains methods for Plugin.
|
2
|
-
|
3
|
-
module Embulk::Guess
|
4
|
-
module SchemaGuess
|
5
|
-
class << self
|
6
|
-
|
7
|
-
# NOTE: Original #from_hash_records uses keys of the first record only,
|
8
|
-
# but JSON from JIRA API has fields which of value is sometimes nil,
|
9
|
-
# sometimes JSON,
|
10
|
-
# so the first record doesn't have all key for guess always.
|
11
|
-
# original Embulk::Guess::SchemaGuess is https://github.com/embulk/embulk/blob/57b42c31d1d539177e1e818f294550cde5b69e1f/lib/embulk/guess/schema_guess.rb#L16-L24
|
12
|
-
def from_hash_records(array_of_hash)
|
13
|
-
array_of_hash = Array(array_of_hash)
|
14
|
-
if array_of_hash.empty?
|
15
|
-
raise "SchemaGuess Can't guess schema from no records"
|
16
|
-
end
|
17
|
-
column_names = array_of_hash.map(&:keys).inject([]) {|r, a| r + a }.uniq.sort
|
18
|
-
samples = array_of_hash.to_a.map {|hash| column_names.map {|name| hash[name] } }
|
19
|
-
from_array_records(column_names, samples)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
module Embulk
|
26
|
-
module Input
|
27
|
-
module JiraInputPluginUtils
|
28
|
-
# Guess::SchemaGuess.from_hash_records returns Columns
|
29
|
-
# containing 'index' key, but it is needless.
|
30
|
-
def self.guess_columns(records)
|
31
|
-
schema = Guess::SchemaGuess.from_hash_records(records)
|
32
|
-
|
33
|
-
schema.map do |c|
|
34
|
-
column = {name: c.name, type: c.type}
|
35
|
-
column[:format] = c.format if c.format
|
36
|
-
column
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
def self.cast(value, type)
|
41
|
-
return value if value.nil?
|
42
|
-
|
43
|
-
case type.to_sym
|
44
|
-
when :long
|
45
|
-
Integer(value)
|
46
|
-
when :double
|
47
|
-
Float(value)
|
48
|
-
when :timestamp
|
49
|
-
Time.parse(value)
|
50
|
-
when :boolean
|
51
|
-
!!value
|
52
|
-
else
|
53
|
-
value.to_s
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
@@ -1,89 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
describe Embulk::Input::JiraInputPluginUtils do
|
4
|
-
describe ".guess_columns" do
|
5
|
-
subject do
|
6
|
-
Embulk::Input::JiraInputPluginUtils.guess_columns(records)
|
7
|
-
end
|
8
|
-
|
9
|
-
let(:records) do
|
10
|
-
[
|
11
|
-
{"project.key" => "FOO-1", "comment.total" => 3, "created" => "2015-03-01T00:12:00"},
|
12
|
-
{"project.id" => "1", "project.key" => "FOO", "comment.total" => 3, "created" => "2015-03-01T00:12:00"}
|
13
|
-
]
|
14
|
-
end
|
15
|
-
|
16
|
-
let(:expected) do
|
17
|
-
[
|
18
|
-
{name: "comment.total", type: :long},
|
19
|
-
{name: "created", type: :timestamp, format: "%Y-%m-%dT%H:%M:%S"},
|
20
|
-
{name: "project.id", type: :long},
|
21
|
-
{name: "project.key", type: :string},
|
22
|
-
]
|
23
|
-
end
|
24
|
-
|
25
|
-
it "returns Array containing columns without 'index' key from each record" do
|
26
|
-
expect(subject).to eq expected
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
describe ".cast" do
|
31
|
-
subject do
|
32
|
-
Embulk::Input::JiraInputPluginUtils.cast(value, type)
|
33
|
-
end
|
34
|
-
|
35
|
-
context "when value is nil" do
|
36
|
-
let(:value) { nil }
|
37
|
-
let(:type) { :string }
|
38
|
-
|
39
|
-
it "returns nil" do
|
40
|
-
expect(subject).to be_nil
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
context "when value is not nil" do
|
45
|
-
let(:value) { 123 }
|
46
|
-
|
47
|
-
context "and type is :string" do
|
48
|
-
let(:type) { :string }
|
49
|
-
|
50
|
-
it "returns '123'" do
|
51
|
-
expect(subject).to eq "123"
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
context "and type is :long" do
|
56
|
-
let(:type) { :long }
|
57
|
-
|
58
|
-
it "returns 123" do
|
59
|
-
expect(subject).to eq 123
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
context "and type is :double" do
|
64
|
-
let(:type) { :double }
|
65
|
-
|
66
|
-
it "returns 123.0" do
|
67
|
-
expect(subject).to eq 123.0
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
context "and type is :timestamp" do
|
72
|
-
let(:value) { "2015-03-01T00:12:00" }
|
73
|
-
let(:type) { :timestamp }
|
74
|
-
|
75
|
-
it "returns Time object" do
|
76
|
-
expect(subject).to eq Time.new(2015, 3, 1, 0, 12, 0)
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
context "and type is :boolean" do
|
81
|
-
let(:type) { :boolean }
|
82
|
-
|
83
|
-
it "returns true" do
|
84
|
-
expect(subject).to be true
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|