crate_ruby 0.0.9 → 0.1.0
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 +5 -5
- data/.travis.yml +3 -2
- data/DEVELOP.rst +1 -1
- data/README.rst +23 -0
- data/crate_ruby.gemspec +1 -1
- data/devtools/create_tag.sh +1 -1
- data/history.txt +2 -0
- data/lib/crate_ruby.rb +2 -6
- data/lib/crate_ruby/client.rb +86 -63
- data/lib/crate_ruby/error.rb +0 -2
- data/lib/crate_ruby/result_set.rb +4 -6
- data/lib/crate_ruby/version.rb +1 -2
- data/spec/bootstrap.rb +7 -12
- data/spec/crate_ruby/client_spec.rb +93 -38
- data/spec/crate_ruby/result_set_spec.rb +7 -16
- data/spec/spec_helper.rb +20 -1
- data/spec/support/test_cluster.rb +107 -0
- metadata +6 -5
- data/lib/crate_ruby/utils.rb +0 -117
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 527d9c75e305c5d0bdff4ad77d5a8268ee2e172926dc252e8f2c7cff19e4189c
|
4
|
+
data.tar.gz: 99454b1e16d97746418602c7c82fb6feeb56dd9dfaddaa4259635928d9a9ffcf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 39fc95a25b3efb6630454bb7f6c120f6d8e980d67ab4442a147b48c783ca534fd929e8a0f030c57e22d5a6ca860da9f1ba3dc7fa0471360d48c0c47ad990a8fe
|
7
|
+
data.tar.gz: 6075a190c28ed1ff3b4ad455b9db7413abb67f1afc29bffcb1f61d1ae43fd7e177cee54f5c318545cf17c526f2176a77d179e80765733245fdafc41fe7ec0d9d
|
data/.travis.yml
CHANGED
data/DEVELOP.rst
CHANGED
data/README.rst
CHANGED
@@ -82,6 +82,29 @@ Manipulate BLOBs like so::
|
|
82
82
|
# deletion
|
83
83
|
client.blob_delete(table_name, digest)
|
84
84
|
|
85
|
+
Schema support
|
86
|
+
|
87
|
+
A default schema can be set by passing in the schema name::
|
88
|
+
|
89
|
+
CrateRuby::Client.new(['localhost:44200'], schema: 'my_schema')
|
90
|
+
|
91
|
+
Authentication
|
92
|
+
|
93
|
+
Authentication credentials can be passed to the client if needed::
|
94
|
+
|
95
|
+
CrateRuby::Client.new(['localhost:44200'], username: 'foo', password: 'supersecret')
|
96
|
+
|
97
|
+
|
98
|
+
Version matrix
|
99
|
+
==============
|
100
|
+
+--------------+------------+
|
101
|
+
| Crate Ruby | CrateDB |
|
102
|
+
+==============+============+
|
103
|
+
| < 0.9 | < 0.57 |
|
104
|
+
+--------------+------------+
|
105
|
+
| 0.9 | >= 0.57 |
|
106
|
+
+--------------+------------+
|
107
|
+
|
85
108
|
Contributing
|
86
109
|
============
|
87
110
|
|
data/crate_ruby.gemspec
CHANGED
@@ -31,7 +31,7 @@ Gem::Specification.new do |spec|
|
|
31
31
|
spec.summary = "A simple interface for the Crate.IO database."
|
32
32
|
spec.description = "A Ruby interface for Crate.IO. Put your data to work. Simply."
|
33
33
|
spec.homepage = "http://crate.io"
|
34
|
-
spec.license = "Apache
|
34
|
+
spec.license = "Apache-2.0"
|
35
35
|
spec.required_ruby_version = '>= 2.0'
|
36
36
|
|
37
37
|
spec.files = `git ls-files -z`.split("\x0")
|
data/devtools/create_tag.sh
CHANGED
@@ -48,7 +48,7 @@ fi
|
|
48
48
|
|
49
49
|
# get version from version.rb
|
50
50
|
VERSION=$(grep "VERSION =" lib/crate_ruby/version.rb | \
|
51
|
-
cut -d' ' -f5 | tr -d "\'")
|
51
|
+
cut -d' ' -f5 | tr -d "\'" | sed -e "s/.freeze//")
|
52
52
|
echo "Version: $VERSION"
|
53
53
|
|
54
54
|
# check if tag to create has already been created
|
data/history.txt
CHANGED
data/lib/crate_ruby.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# -*- coding: utf-8; -*-
|
2
1
|
#
|
3
2
|
# Licensed to CRATE Technology GmbH ("Crate") under one or more contributor
|
4
3
|
# license agreements. See the NOTICE file distributed with this work for
|
@@ -19,16 +18,14 @@
|
|
19
18
|
# with Crate these terms will supersede the license and you may use the
|
20
19
|
# software solely pursuant to the terms of the relevant commercial agreement.
|
21
20
|
|
22
|
-
require
|
23
|
-
require
|
21
|
+
require 'crate_ruby/version'
|
22
|
+
require 'crate_ruby/error'
|
24
23
|
require 'crate_ruby/result_set'
|
25
24
|
require 'crate_ruby/client'
|
26
|
-
require 'crate_ruby/utils'
|
27
25
|
|
28
26
|
include CrateRuby
|
29
27
|
|
30
28
|
module CrateRuby
|
31
|
-
|
32
29
|
def self.logger
|
33
30
|
@logger ||= begin
|
34
31
|
require 'logger'
|
@@ -41,5 +38,4 @@ module CrateRuby
|
|
41
38
|
def self.logger=(logger)
|
42
39
|
@logger = logger
|
43
40
|
end
|
44
|
-
|
45
41
|
end
|
data/lib/crate_ruby/client.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# -*- coding: utf-8; -*-
|
2
1
|
#
|
3
2
|
# Licensed to CRATE Technology GmbH ("Crate") under one or more contributor
|
4
3
|
# license agreements. See the NOTICE file distributed with this work for
|
@@ -21,99 +20,114 @@
|
|
21
20
|
|
22
21
|
require 'json'
|
23
22
|
require 'net/http'
|
23
|
+
require 'base64'
|
24
|
+
|
24
25
|
module CrateRuby
|
26
|
+
# Client to interact with Crate.io DB
|
25
27
|
class Client
|
26
|
-
DEFAULT_HOST =
|
27
|
-
DEFAULT_PORT =
|
28
|
+
DEFAULT_HOST = '127.0.0.1'.freeze
|
29
|
+
DEFAULT_PORT = '4200'.freeze
|
28
30
|
|
29
|
-
attr_accessor :logger
|
31
|
+
attr_accessor :logger, :schema, :username, :password
|
30
32
|
|
31
33
|
# Currently only a single server is supported. Fail over will be implemented in upcoming versions
|
32
34
|
# @param [Array] servers An Array of servers including ports [127.0.0.1:4200, 10.0.0.1:4201]
|
33
|
-
# @param [opts] Optional
|
35
|
+
# @param [opts] opts Optional parameters
|
34
36
|
# * logger: Custom Logger
|
35
37
|
# * http_options [Hash]: Net::HTTP options (open_timeout, read_timeout)
|
38
|
+
# * schema [String]: Default schema to search in
|
36
39
|
# @return [CrateRuby::Client]
|
37
40
|
def initialize(servers = [], opts = {})
|
38
41
|
@servers = servers
|
39
42
|
@servers << "#{DEFAULT_HOST}:#{DEFAULT_PORT}" if servers.empty?
|
40
43
|
@logger = opts[:logger] || CrateRuby.logger
|
41
44
|
@http_options = opts[:http_options] || { read_timeout: 3600 }
|
45
|
+
@schema = opts[:schema] || 'doc'
|
46
|
+
@username = opts[:username]
|
47
|
+
@password = opts[:password]
|
42
48
|
end
|
43
49
|
|
44
50
|
def inspect
|
45
|
-
%
|
51
|
+
%(#<CrateRuby::Client:#{object_id}>)
|
46
52
|
end
|
47
53
|
|
48
54
|
# Creates a table
|
49
55
|
# client.create_table "posts", id: [:integer, "primary key"], my_column: :string, my_integer_col: :integer
|
50
56
|
# @param [String] table_name
|
51
57
|
# @param [Hash] column_definition
|
52
|
-
# @option column_definition [String] key sets column name, value sets column type. an array passed as value can
|
58
|
+
# @option column_definition [String] key sets column name, value sets column type. an array passed as value can
|
59
|
+
# be used to set options like primary keys
|
53
60
|
# @return [ResultSet]
|
54
61
|
#
|
55
|
-
def create_table(table_name, column_definition = {}
|
62
|
+
def create_table(table_name, column_definition = {})
|
56
63
|
cols = column_definition.to_a.map { |a| a.join(' ') }.join(', ')
|
57
|
-
stmt = %
|
64
|
+
stmt = %{CREATE TABLE "#{table_name}" (#{cols})}
|
58
65
|
execute(stmt)
|
59
66
|
end
|
60
67
|
|
61
68
|
# Creates a table for storing blobs
|
62
69
|
# @param [String] name Table name
|
63
|
-
# @param [Integer]
|
64
|
-
# @param [Integer]
|
70
|
+
# @param [Integer] shard_count Shard count, defaults to 5
|
71
|
+
# @param [Integer] replicas Number of replicas, defaults to 0
|
65
72
|
# @return [ResultSet]
|
66
73
|
#
|
67
74
|
# client.create_blob_table("blob_table")
|
68
|
-
def create_blob_table(name, shard_count=5, replicas=0)
|
69
|
-
stmt =
|
70
|
-
execute stmt
|
75
|
+
def create_blob_table(name, shard_count = 5, replicas = 0)
|
76
|
+
stmt = %{CREATE BLOB TABLE "#{name}" CLUSTERED INTO ? SHARDS WITH (number_of_replicas=?)}
|
77
|
+
execute stmt, [shard_count, replicas]
|
71
78
|
end
|
72
79
|
|
73
80
|
# Drop table
|
74
81
|
# @param [String] table_name, Name of table to drop
|
75
82
|
# @param [Boolean] blob Needs to be set to true if table is a blob table
|
76
83
|
# @return [ResultSet]
|
77
|
-
def drop_table(table_name, blob=false)
|
78
|
-
tbl = blob ?
|
79
|
-
stmt = %
|
84
|
+
def drop_table(table_name, blob = false)
|
85
|
+
tbl = blob ? 'BLOB TABLE' : 'TABLE'
|
86
|
+
stmt = %(DROP #{tbl} "#{table_name}")
|
80
87
|
execute(stmt)
|
81
88
|
end
|
82
89
|
|
83
90
|
# List all user tables
|
84
91
|
# @return [ResultSet]
|
85
92
|
def show_tables
|
86
|
-
execute(
|
93
|
+
execute('select table_name from information_schema.tables where table_schema = ?', [schema])
|
87
94
|
end
|
88
95
|
|
89
96
|
# Returns all tables in schema 'doc'
|
90
|
-
# @return [Array] Array of table names
|
97
|
+
# @return [Array<String>] Array of table names
|
91
98
|
def tables
|
92
|
-
execute(
|
99
|
+
execute('select table_name from information_schema.tables where table_schema = ?', [schema]).map(&:first)
|
100
|
+
end
|
101
|
+
|
102
|
+
# Returns all tables in schema 'blob'
|
103
|
+
# @return [Array<String>] Array of blob tables
|
104
|
+
def blob_tables
|
105
|
+
execute('select table_name from information_schema.tables where table_schema = ?', ['blob']).map(&:first)
|
93
106
|
end
|
94
107
|
|
95
108
|
# Executes a SQL statement against the Crate HTTP REST endpoint.
|
96
109
|
# @param [String] sql statement to execute
|
97
110
|
# @param [Array] args Array of values used for parameter substitution
|
98
|
-
# @param [
|
111
|
+
# @param [Array] bulk_args List of lists containing records to be processed
|
112
|
+
# @param [Hash] http_options Net::HTTP options (open_timeout, read_timeout)
|
99
113
|
# @return [ResultSet]
|
100
114
|
def execute(sql, args = nil, bulk_args = nil, http_options = {})
|
101
115
|
@logger.debug sql
|
102
|
-
req = Net::HTTP::Post.new(
|
103
|
-
body = {
|
104
|
-
body
|
105
|
-
body
|
116
|
+
req = Net::HTTP::Post.new('/_sql', headers)
|
117
|
+
body = { 'stmt' => sql }
|
118
|
+
body['args'] = args if args
|
119
|
+
body['bulk_args'] = bulk_args if bulk_args
|
106
120
|
req.body = body.to_json
|
107
121
|
response = request(req, http_options)
|
108
122
|
@logger.debug response.body
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
123
|
+
|
124
|
+
case response.code
|
125
|
+
when /^2\d{2}/
|
126
|
+
ResultSet.new response.body
|
127
|
+
else
|
128
|
+
@logger.info(response.body)
|
129
|
+
raise CrateRuby::CrateError, response.body
|
130
|
+
end
|
117
131
|
end
|
118
132
|
|
119
133
|
# Upload a File to a blob table
|
@@ -123,17 +137,16 @@ module CrateRuby
|
|
123
137
|
def blob_put(table, digest, data)
|
124
138
|
uri = blob_path(table, digest)
|
125
139
|
@logger.debug("BLOB PUT #{uri}")
|
126
|
-
req = Net::HTTP::Put.new(blob_path(table, digest))
|
140
|
+
req = Net::HTTP::Put.new(blob_path(table, digest), headers)
|
127
141
|
req.body = data
|
128
142
|
response = request(req)
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
success
|
143
|
+
case response.code
|
144
|
+
when '201'
|
145
|
+
true
|
146
|
+
else
|
147
|
+
@logger.info("Response #{response.code}: " + response.body)
|
148
|
+
false
|
149
|
+
end
|
137
150
|
end
|
138
151
|
|
139
152
|
# Download blob
|
@@ -144,14 +157,14 @@ module CrateRuby
|
|
144
157
|
def blob_get(table, digest)
|
145
158
|
uri = blob_path(table, digest)
|
146
159
|
@logger.debug("BLOB GET #{uri}")
|
147
|
-
req = Net::HTTP::Get.new(uri)
|
160
|
+
req = Net::HTTP::Get.new(uri, headers)
|
148
161
|
response = request(req)
|
149
162
|
case response.code
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
163
|
+
when '200'
|
164
|
+
response.body
|
165
|
+
else
|
166
|
+
@logger.info("Response #{response.code}: #{response.body}")
|
167
|
+
false
|
155
168
|
end
|
156
169
|
end
|
157
170
|
|
@@ -163,31 +176,30 @@ module CrateRuby
|
|
163
176
|
def blob_delete(table, digest)
|
164
177
|
uri = blob_path(table, digest)
|
165
178
|
@logger.debug("BLOB DELETE #{uri}")
|
166
|
-
req = Net::HTTP::Delete.new(uri)
|
179
|
+
req = Net::HTTP::Delete.new(uri, headers)
|
167
180
|
response = request(req)
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
success
|
181
|
+
case response.code
|
182
|
+
when '200'
|
183
|
+
true
|
184
|
+
else
|
185
|
+
@logger.info("Response #{response.code}: #{response.body}")
|
186
|
+
false
|
187
|
+
end
|
176
188
|
end
|
177
189
|
|
178
|
-
|
179
190
|
# Return the table structure
|
180
191
|
# @param [String] table_name Table name to get structure
|
181
192
|
# @param [ResultSet]
|
182
193
|
def table_structure(table_name)
|
183
|
-
execute(
|
194
|
+
execute('select * from information_schema.columns where table_schema = ?' \
|
195
|
+
'AND table_name = ?', [schema, table_name])
|
184
196
|
end
|
185
197
|
|
186
|
-
|
187
198
|
def insert(table_name, attributes)
|
188
199
|
vals = attributes.values
|
189
|
-
|
190
|
-
|
200
|
+
identifiers = attributes.keys.map {|v| %{"#{v}"} }.join(', ')
|
201
|
+
binds = vals.count.times.map { |i| "$#{i + 1}" }.join(',')
|
202
|
+
stmt = %{INSERT INTO "#{table_name}" (#{identifiers}) VALUES(#{binds})}
|
191
203
|
execute(stmt, vals)
|
192
204
|
end
|
193
205
|
|
@@ -207,7 +219,7 @@ module CrateRuby
|
|
207
219
|
end
|
208
220
|
|
209
221
|
def connection
|
210
|
-
host, port = @servers.first.split(':')
|
222
|
+
host, port = @servers.first.split(':')
|
211
223
|
Net::HTTP.new(host, port)
|
212
224
|
end
|
213
225
|
|
@@ -219,5 +231,16 @@ module CrateRuby
|
|
219
231
|
end
|
220
232
|
end
|
221
233
|
|
234
|
+
def headers
|
235
|
+
header = { 'Content-Type' => 'application/json', 'Accept' => 'application/json' }
|
236
|
+
header['Default-Schema'] = schema if schema
|
237
|
+
header['Authorization'] = "Basic #{encrypted_credentials}" if username
|
238
|
+
header['X-User'] = username if username # for backwards compatibility with Crate 2.2
|
239
|
+
header
|
240
|
+
end
|
241
|
+
|
242
|
+
def encrypted_credentials
|
243
|
+
@encrypted_credentials ||= Base64.encode64 "#{username}:#{password}"
|
244
|
+
end
|
222
245
|
end
|
223
246
|
end
|
data/lib/crate_ruby/error.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# -*- coding: utf-8; -*-
|
2
1
|
#
|
3
2
|
# Licensed to CRATE Technology GmbH ("Crate") under one or more contributor
|
4
3
|
# license agreements. See the NOTICE file distributed with this work for
|
@@ -23,5 +22,4 @@ module CrateRuby
|
|
23
22
|
# Base Error class
|
24
23
|
class CrateError < StandardError; end
|
25
24
|
class BlobExistsError < CrateError; end
|
26
|
-
|
27
25
|
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
# -*- coding: utf-8; -*-
|
2
1
|
#
|
3
2
|
# Licensed to CRATE Technology GmbH ("Crate") under one or more contributor
|
4
3
|
# license agreements. See the NOTICE file distributed with this work for
|
@@ -35,7 +34,7 @@ module CrateRuby
|
|
35
34
|
end
|
36
35
|
|
37
36
|
def inspect
|
38
|
-
%
|
37
|
+
%(#<CrateRuby::ResultSet:#{object_id}>, @rowcount="#{@rowcount}", @duration=#{@duration}>)
|
39
38
|
end
|
40
39
|
|
41
40
|
def <<(val)
|
@@ -58,9 +57,8 @@ module CrateRuby
|
|
58
57
|
# @param [Array] ary Column names to filer on
|
59
58
|
# @return [Array] Filtered rows
|
60
59
|
def select_columns(ary, &block)
|
61
|
-
indexes = ary.map {|col| @cols.index(col)}.compact
|
62
|
-
@rows.map{|r| r.values_at(*indexes)}.each(&block)
|
60
|
+
indexes = ary.map { |col| @cols.index(col) }.compact
|
61
|
+
@rows.map { |r| r.values_at(*indexes) }.each(&block)
|
63
62
|
end
|
64
|
-
|
65
63
|
end
|
66
|
-
end
|
64
|
+
end
|
data/lib/crate_ruby/version.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# -*- coding: utf-8; -*-
|
2
1
|
#
|
3
2
|
# Licensed to CRATE Technology GmbH ("Crate") under one or more contributor
|
4
3
|
# license agreements. See the NOTICE file distributed with this work for
|
@@ -20,5 +19,5 @@
|
|
20
19
|
# software solely pursuant to the terms of the relevant commercial agreement.
|
21
20
|
|
22
21
|
module CrateRuby
|
23
|
-
VERSION = '0.0.
|
22
|
+
VERSION = '0.1.0'.freeze
|
24
23
|
end
|
data/spec/bootstrap.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
# -*- coding: utf-8; -*-
|
3
2
|
#
|
4
3
|
# Licensed to CRATE Technology GmbH ("Crate") under one or more contributor
|
5
4
|
# license agreements. See the NOTICE file distributed with this work for
|
@@ -25,8 +24,7 @@ require 'net/http'
|
|
25
24
|
require 'zlib'
|
26
25
|
|
27
26
|
class Bootstrap
|
28
|
-
|
29
|
-
VERSION = '2.1.8'
|
27
|
+
VERSION = '2.3.0'.freeze
|
30
28
|
|
31
29
|
def initialize
|
32
30
|
@fname = "crate-#{VERSION}.tar.gz"
|
@@ -34,10 +32,8 @@ class Bootstrap
|
|
34
32
|
end
|
35
33
|
|
36
34
|
def run
|
37
|
-
|
38
|
-
|
39
|
-
download
|
40
|
-
end
|
35
|
+
unless File.file?(@crate_bin)
|
36
|
+
download unless File.file?(@fname)
|
41
37
|
extract
|
42
38
|
end
|
43
39
|
end
|
@@ -45,10 +41,10 @@ class Bootstrap
|
|
45
41
|
def download
|
46
42
|
uri = URI("https://cdn.crate.io/downloads/releases/#{@fname}")
|
47
43
|
puts "Downloading Crate from #{uri} ..."
|
48
|
-
Net::HTTP.start(uri.host, uri.port, :
|
44
|
+
Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
|
49
45
|
request = Net::HTTP::Get.new uri
|
50
46
|
resp = http.request request
|
51
|
-
open(@fname,
|
47
|
+
open(@fname, 'wb') do |file|
|
52
48
|
file.write(resp.body)
|
53
49
|
end
|
54
50
|
end
|
@@ -65,7 +61,7 @@ class Bootstrap
|
|
65
61
|
else
|
66
62
|
dest_dir = File.dirname(dest_file)
|
67
63
|
FileUtils.mkdir_p dest_dir unless File.directory?(dest_dir)
|
68
|
-
File.open dest_file,
|
64
|
+
File.open dest_file, 'wb' do |f|
|
69
65
|
f.print entry.read
|
70
66
|
end
|
71
67
|
end
|
@@ -75,5 +71,4 @@ class Bootstrap
|
|
75
71
|
end
|
76
72
|
|
77
73
|
bootstrap = Bootstrap.new(*ARGV)
|
78
|
-
bootstrap.run
|
79
|
-
|
74
|
+
bootstrap.run
|
@@ -1,4 +1,3 @@
|
|
1
|
-
# -*- coding: utf-8; -*-
|
2
1
|
#
|
3
2
|
# Licensed to CRATE Technology GmbH ("Crate") under one or more contributor
|
4
3
|
# license agreements. See the NOTICE file distributed with this work for
|
@@ -24,18 +23,9 @@ require 'securerandom'
|
|
24
23
|
|
25
24
|
describe CrateRuby::Client do
|
26
25
|
let(:client) { CrateRuby::Client.new(['localhost:44200']) }
|
27
|
-
|
28
|
-
before(:all) do
|
29
|
-
@cluster = CrateRuby::TestCluster.new(1)
|
30
|
-
@cluster.start_nodes
|
31
|
-
end
|
32
|
-
|
33
|
-
after(:all) do
|
34
|
-
@cluster.stop_nodes
|
35
|
-
end
|
26
|
+
let(:client_w_schema) { CrateRuby::Client.new(['localhost:44200'], schema: 'custom') }
|
36
27
|
|
37
28
|
describe '#create_table' do
|
38
|
-
|
39
29
|
describe 'blob management' do
|
40
30
|
let(:file) { 'logo-crate.png' }
|
41
31
|
let(:path) { File.join(File.dirname(__FILE__), '../uploads/') }
|
@@ -60,7 +50,7 @@ describe CrateRuby::Client do
|
|
60
50
|
end
|
61
51
|
end
|
62
52
|
context '#string' do
|
63
|
-
let(:string) {
|
53
|
+
let(:string) { 'my crazy' }
|
64
54
|
let(:digest) { Digest::SHA1.hexdigest(string) }
|
65
55
|
it 'should upload a string to the blob table' do
|
66
56
|
client.blob_put(@blob_table, digest, string).should be_truthy
|
@@ -76,9 +66,9 @@ describe CrateRuby::Client do
|
|
76
66
|
it 'should download a blob' do
|
77
67
|
data = client.blob_get(@blob_table, digest)
|
78
68
|
data.should_not be_falsey
|
79
|
-
open(store_location,
|
69
|
+
open(store_location, 'wb') do |file|
|
80
70
|
file.write(data)
|
81
|
-
|
71
|
+
end
|
82
72
|
end
|
83
73
|
end
|
84
74
|
|
@@ -93,12 +83,12 @@ describe CrateRuby::Client do
|
|
93
83
|
end
|
94
84
|
end
|
95
85
|
|
96
|
-
|
97
86
|
describe '#execute' do
|
98
|
-
let(:table_name) {
|
87
|
+
let(:table_name) { 't_test' }
|
99
88
|
|
100
89
|
before do
|
101
|
-
client.execute("create table #{table_name}
|
90
|
+
client.execute("create table #{table_name} " \
|
91
|
+
'(id integer primary key, name string, address object, tags array(string)) ')
|
102
92
|
end
|
103
93
|
|
104
94
|
after do
|
@@ -107,49 +97,70 @@ describe CrateRuby::Client do
|
|
107
97
|
|
108
98
|
it 'should allow parameters' do
|
109
99
|
client.execute("insert into #{table_name} (id, name, address, tags) VALUES (?, ?, ?, ?)",
|
110
|
-
[1,
|
100
|
+
[1, 'Post 1', { street: '1010 W 2nd Ave', city: 'Vancouver' },
|
101
|
+
%w[awesome freaky]]).should be_truthy
|
111
102
|
client.refresh_table table_name
|
112
103
|
client.execute("select * from #{table_name}").rowcount.should eq(1)
|
113
104
|
end
|
114
105
|
|
115
106
|
it 'should allow bulk parameters' do
|
116
107
|
bulk_args = [
|
117
|
-
[1,
|
118
|
-
[2,
|
108
|
+
[1, 'Post 1', { street: '1010 W 2nd Ave', city: 'New York' }, %w[foo bar]],
|
109
|
+
[2, 'Post 2', { street: '1010 W 2nd Ave', city: 'San Fran' }, []]
|
119
110
|
]
|
120
|
-
client.execute("insert into #{table_name} (id, name, address, tags) VALUES (?, ?, ?, ?)",
|
111
|
+
client.execute("insert into #{table_name} (id, name, address, tags) VALUES (?, ?, ?, ?)",
|
112
|
+
nil, bulk_args).should be_truthy
|
121
113
|
client.refresh_table table_name
|
122
114
|
client.execute("select * from #{table_name}").rowcount.should eq(2)
|
123
115
|
client.execute("select count(*) from #{table_name}")[0][0].should eq(2)
|
124
116
|
end
|
125
117
|
|
126
118
|
it 'should accept http options' do
|
127
|
-
expect
|
119
|
+
expect do
|
120
|
+
client.execute("select * from #{table_name}", nil, nil,
|
121
|
+
'read_timeout' => 0)
|
122
|
+
end.to raise_error Net::ReadTimeout
|
128
123
|
end
|
129
|
-
end
|
130
124
|
|
125
|
+
context 'with schema' do
|
126
|
+
before do
|
127
|
+
client_w_schema.execute("create table #{table_name} \n
|
128
|
+
(id integer primary key, name string, address object, tags array(string)) ")
|
129
|
+
end
|
130
|
+
after { client_w_schema.execute("drop table #{table_name}") }
|
131
|
+
|
132
|
+
it 'should allow parameters' do
|
133
|
+
client_w_schema.execute("insert into #{table_name} (id, name, address, tags) VALUES (?, ?, ?, ?)",
|
134
|
+
[1, 'Post 1', { street: '1010 W 2nd Ave', city: 'Vancouver' },
|
135
|
+
%w[awesome freaky]]).should be_truthy
|
136
|
+
client_w_schema.refresh_table table_name
|
137
|
+
client.execute("select * from #{table_name}").rowcount.should_not eq(1)
|
138
|
+
client_w_schema.execute("select * from #{table_name}").rowcount.should eq(1)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
131
142
|
|
132
143
|
describe '#initialize' do
|
133
144
|
it 'should use host and ports parameters' do
|
134
|
-
logger = double
|
135
|
-
client = CrateRuby::Client.new [
|
136
|
-
client.instance_variable_get(:@servers).should eq([
|
145
|
+
logger = double
|
146
|
+
client = CrateRuby::Client.new ['10.0.0.1:4200'], logger: logger
|
147
|
+
client.instance_variable_get(:@servers).should eq(['10.0.0.1:4200'])
|
137
148
|
end
|
138
149
|
it 'should use default request parameters' do
|
139
150
|
client = CrateRuby::Client.new
|
140
|
-
client.instance_variable_get(:@http_options).should eq(
|
151
|
+
client.instance_variable_get(:@http_options).should eq(read_timeout: 3600)
|
141
152
|
end
|
142
153
|
it 'should use request parameters' do
|
143
154
|
client = CrateRuby::Client.new ['10.0.0.1:4200'],
|
144
|
-
|
145
|
-
client.instance_variable_get(:@http_options).should eq(
|
155
|
+
http_options: { read_timeout: 60 }
|
156
|
+
client.instance_variable_get(:@http_options).should eq(read_timeout: 60)
|
146
157
|
end
|
147
158
|
end
|
148
159
|
|
149
160
|
describe '#tables' do
|
150
161
|
before do
|
151
|
-
client.create_table
|
152
|
-
client.create_table
|
162
|
+
client.create_table 'posts', id: :integer
|
163
|
+
client.create_table 'comments', id: :integer
|
153
164
|
end
|
154
165
|
|
155
166
|
after do
|
@@ -159,26 +170,38 @@ describe CrateRuby::Client do
|
|
159
170
|
end
|
160
171
|
|
161
172
|
it 'should return all user tables as an array of string values' do
|
162
|
-
client.tables.should eq %w
|
173
|
+
client.tables.should eq %w[comments posts]
|
163
174
|
end
|
164
175
|
end
|
165
176
|
|
177
|
+
describe '#blob_tables' do
|
178
|
+
before do
|
179
|
+
client.create_blob_table 'pix'
|
180
|
+
end
|
181
|
+
|
182
|
+
after do
|
183
|
+
client.drop_table 'pix', true
|
184
|
+
end
|
185
|
+
|
186
|
+
it 'should return all user tables as an array of string values' do
|
187
|
+
client.blob_tables.should eq %w(pix)
|
188
|
+
end
|
189
|
+
end
|
166
190
|
|
167
191
|
describe '#insert' do
|
168
192
|
before do
|
169
|
-
client.create_table(
|
170
|
-
|
171
|
-
views: :integer)
|
193
|
+
client.create_table('posts', id: [:string, 'primary key'],
|
194
|
+
title: :string, views: :integer)
|
172
195
|
end
|
173
196
|
|
174
197
|
after do
|
175
|
-
client.drop_table
|
198
|
+
client.drop_table 'posts'
|
176
199
|
end
|
177
200
|
|
178
201
|
it 'should insert the record' do
|
179
202
|
expect do
|
180
203
|
id = SecureRandom.uuid
|
181
|
-
client.insert('posts', id: id, title:
|
204
|
+
client.insert('posts', id: id, title: 'Test')
|
182
205
|
client.refresh_table('posts')
|
183
206
|
result_set = client.execute("Select * from posts where id = '#{id}'")
|
184
207
|
result_set.rowcount.should eq 1
|
@@ -188,10 +211,42 @@ describe CrateRuby::Client do
|
|
188
211
|
|
189
212
|
describe '#refresh table' do
|
190
213
|
it 'should issue the proper refresh statment' do
|
191
|
-
client.should_receive(:execute).with(
|
214
|
+
client.should_receive(:execute).with('refresh table posts')
|
192
215
|
client.refresh_table('posts')
|
193
216
|
end
|
194
217
|
end
|
218
|
+
end
|
219
|
+
|
220
|
+
describe 'authentication' do
|
221
|
+
let(:username) { 'matz' }
|
222
|
+
let(:password) { 'ruby' }
|
223
|
+
let(:encrypted_credentials) { Base64.encode64 "#{username}:#{password}" }
|
195
224
|
|
225
|
+
describe 'with password' do
|
226
|
+
let(:auth_client) { CrateRuby::Client.new(['localhost:44200'], username: username, password: password) }
|
227
|
+
it 'sets the basic auth header' do
|
228
|
+
headers = auth_client.send(:headers)
|
229
|
+
expect(headers['Authorization']).to eq "Basic #{encrypted_credentials}"
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
describe 'without password' do
|
234
|
+
let(:auth_client) { CrateRuby::Client.new(['localhost:44200'], username: username) }
|
235
|
+
let(:enc_creds_wo_pwd) { Base64.encode64 "#{username}:" }
|
236
|
+
|
237
|
+
it 'sets and encodes auth header even without password' do
|
238
|
+
headers = auth_client.send(:headers)
|
239
|
+
expect(headers['Authorization']).to eq "Basic #{enc_creds_wo_pwd}"
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
describe 'X-User header' do
|
244
|
+
let(:auth_client) { CrateRuby::Client.new(['localhost:44200'], username: username) }
|
245
|
+
|
246
|
+
it 'sets the X-User header' do
|
247
|
+
headers = auth_client.send(:headers)
|
248
|
+
expect(headers['X-User']).to eq username
|
249
|
+
end
|
250
|
+
end
|
196
251
|
end
|
197
252
|
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
# -*- coding: utf-8; -*-
|
2
1
|
#
|
3
2
|
# Licensed to CRATE Technology GmbH ("Crate") under one or more contributor
|
4
3
|
# license agreements. See the NOTICE file distributed with this work for
|
@@ -22,18 +21,15 @@
|
|
22
21
|
require_relative '../spec_helper'
|
23
22
|
|
24
23
|
describe ResultSet do
|
25
|
-
|
26
|
-
let(:
|
27
|
-
let(:
|
28
|
-
let(:result_with_object) { %Q{{"cols":["address","id","name"],"rows":[[{"street":"1010 W 2nd Ave","city":"Vancouver"},"fb7183ac-d049-462c-85a9-732aca59a1c1","Mad Max"]],"rowcount":1,"duration":3}} }
|
24
|
+
let(:crate_result) { '{"cols":["my_column","my_integer_col"],"rows":[["Foo",5],["Bar",5]],"rowcount":1,"duration":4}' }
|
25
|
+
let(:result_with_array_col) { %({"cols":["id","tags","title"],"rows":[[1,["awesome","freaky"],"My life with crate"]],"rowcount":1,"duration":2}) }
|
26
|
+
let(:result_with_object) { %({"cols":["address","id","name"],"rows":[[{"street":"1010 W 2nd Ave","city":"Vancouver"},"fb7183ac-d049-462c-85a9-732aca59a1c1","Mad Max"]],"rowcount":1,"duration":3}) }
|
29
27
|
|
30
28
|
let(:result_set) { ResultSet.new(crate_result) }
|
31
29
|
|
32
30
|
let(:json_result) { JSON.parse crate_result }
|
33
31
|
|
34
32
|
describe '#initialize' do
|
35
|
-
|
36
|
-
|
37
33
|
it 'should set rowcount' do
|
38
34
|
result_set.rowcount.should eq 1
|
39
35
|
end
|
@@ -49,15 +45,14 @@ describe ResultSet do
|
|
49
45
|
it 'should parse an array column result into an Array' do
|
50
46
|
res = ResultSet.new(result_with_array_col)
|
51
47
|
res[0][1].should be_a(Array)
|
52
|
-
res[0][1].should eq([
|
48
|
+
res[0][1].should eq(%w[awesome freaky])
|
53
49
|
end
|
54
50
|
|
55
51
|
it 'should parse an object column result into an Object' do
|
56
52
|
res = ResultSet.new(result_with_object)
|
57
53
|
res[0][0].should be_a(Hash)
|
58
|
-
res[0][0].should eq(
|
54
|
+
res[0][0].should eq('street' => '1010 W 2nd Ave', 'city' => 'Vancouver')
|
59
55
|
end
|
60
|
-
|
61
56
|
end
|
62
57
|
|
63
58
|
describe '#each' do
|
@@ -80,12 +75,11 @@ describe ResultSet do
|
|
80
75
|
result_set.select_columns(['my_column']) do |res|
|
81
76
|
a << res
|
82
77
|
end
|
83
|
-
a.should eq [[
|
84
|
-
|
78
|
+
a.should eq [['Foo'], ['Bar']]
|
85
79
|
end
|
86
80
|
it 'should not raise error on invalid column name' do
|
87
81
|
expect do
|
88
|
-
result_set.select_columns([
|
82
|
+
result_set.select_columns(%w[my_column invalid]) do |row|
|
89
83
|
end
|
90
84
|
end.to_not raise_error
|
91
85
|
end
|
@@ -96,7 +90,4 @@ describe ResultSet do
|
|
96
90
|
result_set.values.should eq json_result['rows']
|
97
91
|
end
|
98
92
|
end
|
99
|
-
|
100
93
|
end
|
101
|
-
|
102
|
-
|
data/spec/spec_helper.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# -*- coding: utf-8; -*-
|
2
1
|
#
|
3
2
|
# Licensed to CRATE Technology GmbH ("Crate") under one or more contributor
|
4
3
|
# license agreements. See the NOTICE file distributed with this work for
|
@@ -21,4 +20,24 @@
|
|
21
20
|
|
22
21
|
require_relative '../lib/crate_ruby'
|
23
22
|
require 'net/http'
|
23
|
+
require_relative 'support/test_cluster'
|
24
24
|
|
25
|
+
HOST = '127.0.0.1'.freeze
|
26
|
+
PORT = 44_200
|
27
|
+
|
28
|
+
RSpec.configure do |config|
|
29
|
+
config.before(:each) do
|
30
|
+
end
|
31
|
+
config.after(:each) do
|
32
|
+
end
|
33
|
+
config.before(:suite) do
|
34
|
+
@cluster = TestCluster.new(1, PORT)
|
35
|
+
@cluster.start_nodes
|
36
|
+
end
|
37
|
+
config.after(:suite) do
|
38
|
+
pid_file = File.join(__dir__, 'support/testnode.pid')
|
39
|
+
pid = File.read(pid_file)
|
40
|
+
File.delete(pid_file)
|
41
|
+
Process.kill('HUP', pid.to_i)
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Licensed to CRATE Technology GmbH ("Crate") under one or more contributor
|
4
|
+
# license agreements. See the NOTICE file distributed with this work for
|
5
|
+
# additional information regarding copyright ownership. Crate licenses
|
6
|
+
# this file to you under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License. You may
|
8
|
+
# obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
14
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
15
|
+
# License for the specific language governing permissions and limitations
|
16
|
+
# under the License.
|
17
|
+
#
|
18
|
+
# However, if you have executed another commercial license agreement
|
19
|
+
# with Crate these terms will supersede the license and you may use the
|
20
|
+
# software solely pursuant to the terms of the relevant commercial agreement.
|
21
|
+
|
22
|
+
require 'net/http'
|
23
|
+
|
24
|
+
class TestCluster
|
25
|
+
def initialize(num_nodes = 1, http_port = 44_200)
|
26
|
+
@nodes = []
|
27
|
+
idx = 0
|
28
|
+
while idx < num_nodes
|
29
|
+
name = "crate#{idx - 1}"
|
30
|
+
port = http_port + idx
|
31
|
+
@nodes << TestServer.new(name, port)
|
32
|
+
idx += 1
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def start_nodes
|
37
|
+
@nodes.each(&:start)
|
38
|
+
end
|
39
|
+
|
40
|
+
def stop_nodes
|
41
|
+
@nodes.each(&:stop)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class TestServer
|
46
|
+
STARTUP_TIMEOUT = 30
|
47
|
+
|
48
|
+
def initialize(name, http_port)
|
49
|
+
@node_name = name
|
50
|
+
@http_port = http_port
|
51
|
+
|
52
|
+
@crate_bin = File.join('parts', 'crate', 'bin', 'crate')
|
53
|
+
unless File.file?(@crate_bin)
|
54
|
+
puts "Crate is not available. Please run 'bundle exec ruby spec/bootstrap.rb' first."
|
55
|
+
exit 1
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def start
|
60
|
+
cmd = "sh #{@crate_bin} #{start_params}"
|
61
|
+
@pid = spawn(cmd)
|
62
|
+
wait_for
|
63
|
+
Process.detach(@pid)
|
64
|
+
|
65
|
+
File.write(__dir__ + '/testnode.pid', @pid)
|
66
|
+
end
|
67
|
+
|
68
|
+
def wait_for
|
69
|
+
time_slept = 0
|
70
|
+
interval = 1
|
71
|
+
loop do
|
72
|
+
if !alive? && (time_slept > STARTUP_TIMEOUT)
|
73
|
+
puts "Crate hasn't started for #{STARTUP_TIMEOUT} seconds. Giving up now..."
|
74
|
+
exit 1
|
75
|
+
end
|
76
|
+
if alive?
|
77
|
+
break
|
78
|
+
else
|
79
|
+
sleep(interval)
|
80
|
+
time_slept += interval
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def stop
|
86
|
+
Process.kill('HUP', @pid)
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def start_params
|
92
|
+
"-Cnode.name=#{@node_name} " \
|
93
|
+
"-Chttp.port=#{@http_port} " \
|
94
|
+
'-Cnetwork.host=localhost '
|
95
|
+
end
|
96
|
+
|
97
|
+
def alive?
|
98
|
+
req = Net::HTTP::Get.new('/')
|
99
|
+
resp = Net::HTTP.new('localhost', @http_port)
|
100
|
+
begin
|
101
|
+
response = resp.start { |http| http.request(req) }
|
102
|
+
response.code == '200'
|
103
|
+
rescue Errno::ECONNREFUSED
|
104
|
+
false
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: crate_ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Christoph Klocker
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2018-01-23 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -62,19 +62,19 @@ files:
|
|
62
62
|
- lib/crate_ruby/client.rb
|
63
63
|
- lib/crate_ruby/error.rb
|
64
64
|
- lib/crate_ruby/result_set.rb
|
65
|
-
- lib/crate_ruby/utils.rb
|
66
65
|
- lib/crate_ruby/version.rb
|
67
66
|
- log/.keep
|
68
67
|
- spec/bootstrap.rb
|
69
68
|
- spec/crate_ruby/client_spec.rb
|
70
69
|
- spec/crate_ruby/result_set_spec.rb
|
71
70
|
- spec/spec_helper.rb
|
71
|
+
- spec/support/test_cluster.rb
|
72
72
|
- spec/uploads/get_logo-crate.png
|
73
73
|
- spec/uploads/logo-crate.png
|
74
74
|
- spec/uploads/text.txt
|
75
75
|
homepage: http://crate.io
|
76
76
|
licenses:
|
77
|
-
- Apache
|
77
|
+
- Apache-2.0
|
78
78
|
metadata: {}
|
79
79
|
post_install_message:
|
80
80
|
rdoc_options: []
|
@@ -92,7 +92,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
92
92
|
version: '0'
|
93
93
|
requirements: []
|
94
94
|
rubyforge_project:
|
95
|
-
rubygems_version: 2.
|
95
|
+
rubygems_version: 2.7.4
|
96
96
|
signing_key:
|
97
97
|
specification_version: 4
|
98
98
|
summary: A simple interface for the Crate.IO database.
|
@@ -101,6 +101,7 @@ test_files:
|
|
101
101
|
- spec/crate_ruby/client_spec.rb
|
102
102
|
- spec/crate_ruby/result_set_spec.rb
|
103
103
|
- spec/spec_helper.rb
|
104
|
+
- spec/support/test_cluster.rb
|
104
105
|
- spec/uploads/get_logo-crate.png
|
105
106
|
- spec/uploads/logo-crate.png
|
106
107
|
- spec/uploads/text.txt
|
data/lib/crate_ruby/utils.rb
DELETED
@@ -1,117 +0,0 @@
|
|
1
|
-
# -*- coding: utf-8; -*-
|
2
|
-
#
|
3
|
-
# Licensed to CRATE Technology GmbH ("Crate") under one or more contributor
|
4
|
-
# license agreements. See the NOTICE file distributed with this work for
|
5
|
-
# additional information regarding copyright ownership. Crate licenses
|
6
|
-
# this file to you under the Apache License, Version 2.0 (the "License");
|
7
|
-
# you may not use this file except in compliance with the License. You may
|
8
|
-
# obtain a copy of the License at
|
9
|
-
#
|
10
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
-
#
|
12
|
-
# Unless required by applicable law or agreed to in writing, software
|
13
|
-
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
14
|
-
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
15
|
-
# License for the specific language governing permissions and limitations
|
16
|
-
# under the License.
|
17
|
-
#
|
18
|
-
# However, if you have executed another commercial license agreement
|
19
|
-
# with Crate these terms will supersede the license and you may use the
|
20
|
-
# software solely pursuant to the terms of the relevant commercial agreement.
|
21
|
-
|
22
|
-
require 'net/http'
|
23
|
-
|
24
|
-
module CrateRuby
|
25
|
-
|
26
|
-
class TestCluster
|
27
|
-
|
28
|
-
def initialize(num_nodes = 1, http_port=44200)
|
29
|
-
@nodes = []
|
30
|
-
idx = 0
|
31
|
-
while idx < num_nodes do
|
32
|
-
name = "crate#{idx-1}"
|
33
|
-
port = http_port + idx
|
34
|
-
@nodes << TestServer.new(name, port)
|
35
|
-
idx += 1
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def start_nodes
|
40
|
-
@nodes.each do |node|
|
41
|
-
node.start
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
def stop_nodes
|
46
|
-
@nodes.each do |node|
|
47
|
-
node.stop
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
end
|
52
|
-
|
53
|
-
class TestServer
|
54
|
-
|
55
|
-
STARTUP_TIMEOUT = 30
|
56
|
-
|
57
|
-
def initialize(name, http_port)
|
58
|
-
@node_name = name
|
59
|
-
@http_port = http_port
|
60
|
-
|
61
|
-
@crate_bin = File.join('parts', 'crate', 'bin', 'crate')
|
62
|
-
if !File.file?(@crate_bin)
|
63
|
-
puts "Crate is not available. Please run 'bundle exec ruby spec/bootstrap.rb' first."
|
64
|
-
exit 1
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
def start
|
69
|
-
cmd = "sh #{@crate_bin} #{start_params}"
|
70
|
-
@pid = spawn(cmd)
|
71
|
-
wait_for
|
72
|
-
Process.detach(@pid)
|
73
|
-
end
|
74
|
-
|
75
|
-
def wait_for
|
76
|
-
time_slept = 0
|
77
|
-
interval = 1
|
78
|
-
while true
|
79
|
-
if !alive? and time_slept > STARTUP_TIMEOUT
|
80
|
-
puts "Crate hasn't started for #{STARTUP_TIMEOUT} seconds. Giving up now..."
|
81
|
-
exit 1
|
82
|
-
end
|
83
|
-
if alive?
|
84
|
-
break
|
85
|
-
else
|
86
|
-
sleep(interval)
|
87
|
-
time_slept += interval
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
def stop
|
93
|
-
Process.kill('HUP', @pid)
|
94
|
-
end
|
95
|
-
|
96
|
-
private
|
97
|
-
|
98
|
-
def start_params
|
99
|
-
"-Cnode.name=#{@node_name} " +
|
100
|
-
"-Chttp.port=#{@http_port} " +
|
101
|
-
"-Cnetwork.host=localhost "
|
102
|
-
end
|
103
|
-
|
104
|
-
def alive?
|
105
|
-
req = Net::HTTP::Get.new('/')
|
106
|
-
resp = Net::HTTP.new('localhost', @http_port)
|
107
|
-
begin
|
108
|
-
response = resp.start { |http| http.request(req) }
|
109
|
-
response.code == "200" ? true : false
|
110
|
-
rescue Errno::ECONNREFUSED
|
111
|
-
false
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
end
|
117
|
-
|