crate_ruby 0.0.9 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
|