Skip to content

Commit

Permalink
Merge acc1fc4 into e4a2639
Browse files Browse the repository at this point in the history
  • Loading branch information
klobuczek committed Jul 12, 2018
2 parents e4a2639 + acc1fc4 commit 7df2f69
Show file tree
Hide file tree
Showing 14 changed files with 129 additions and 87 deletions.
14 changes: 7 additions & 7 deletions .travis.yml
Expand Up @@ -16,7 +16,7 @@ jdk: oraclejdk8
rvm:
- 2.4.2
- 2.1.10
- jruby-9.1.14.0
- jruby-9
env:
global:
- JRUBY_OPTS="-J-Xmx1024m -Xcompile.invokedynamic=false -J-XX:+TieredCompilation -J-XX:TieredStopAtLevel=1 -J-noverify -Xcompile.mode=OFF"
Expand All @@ -43,22 +43,22 @@ matrix:
env: NEO4J_VERSION=community-2.1.8

# Older versions of Neo4j with latest version of jRuby
- rvm: jruby-9.1.14.0
- rvm: jruby-9
env: NEO4J_VERSION=community-3.2.8
- rvm: jruby-9.1.14.0
- rvm: jruby-9
env: NEO4J_VERSION=community-3.1.7
- rvm: jruby-9.1.14.0
- rvm: jruby-9
env: NEO4J_VERSION=community-2.3.11
- rvm: jruby-9.1.14.0
- rvm: jruby-9
env: NEO4J_VERSION=community-2.1.8

# NEW_NEO4J_SESSIONS
- rvm: jruby-9.1.14.0
- rvm: jruby-9
env: RSPEC_OPTS="--tag new_cypher_session" NEO4J_VERSION=community-2.3.11 NEW_NEO4J_SESSIONS=true

# Enterprise
- rvm: 2.4.2
env: NEO4J_VERSION=enterprise-3.2.1
env: NEO4J_VERSION=enterprise-3.4.0

after_failure:
- cat ./db/neo4j/development/logs/neo4j.log
Expand Down
1 change: 1 addition & 0 deletions lib/neo4j/core/cypher_session.rb
Expand Up @@ -2,6 +2,7 @@ module Neo4j
module Core
class CypherSession
attr_reader :adaptor
delegate :close, to: :adaptor

def initialize(adaptor)
fail ArgumentError, "Invalid adaptor: #{adaptor.inspect}" if !adaptor.is_a?(Adaptors::Base)
Expand Down
10 changes: 10 additions & 0 deletions lib/neo4j/core/cypher_session/adaptors.rb
Expand Up @@ -186,6 +186,16 @@ def setup_queries!(queries, transaction, options = {})
("\n#{source_line}:#{line_number}" if payload[:adaptor].options[:verbose_query_logs] && source_line).to_s
end

def default_subscribe
subscribe_to_request
end

def close; end

def supports_metadata?
true
end

class << self
def transaction_class
fail '.transaction_class method not implemented on adaptor!'
Expand Down
27 changes: 2 additions & 25 deletions lib/neo4j/core/cypher_session/adaptors/bolt.rb
@@ -1,5 +1,6 @@
require 'neo4j/core/cypher_session/adaptors'
require 'neo4j/core/cypher_session/adaptors/has_uri'
require 'neo4j/core/cypher_session/adaptors/schema'
require 'neo4j/core/cypher_session/adaptors/bolt/pack_stream'
require 'neo4j/core/cypher_session/adaptors/bolt/chunk_writer_io'
require 'neo4j/core/cypher_session/responses/bolt'
Expand All @@ -12,6 +13,7 @@ class CypherSession
module Adaptors
class Bolt < Base
include Adaptors::HasUri
include Adaptors::Schema
default_url('bolt://neo4:neo4j@localhost:7687')
validate_uri do |uri|
uri.scheme == 'bolt'
Expand Down Expand Up @@ -53,35 +55,10 @@ def query_set(transaction, queries, options = {})
end
end

def version(session)
result = query(session, 'CALL dbms.components()', {}, skip_instrumentation: true)

# BTW: community / enterprise could be retrieved via `result.first.edition`
result.first.versions[0]
end

def connected?
!!@tcp_client && !@tcp_client.closed?
end

def indexes(session)
result = query(session, 'CALL db.indexes()', {}, skip_instrumentation: true)

result.map do |row|
label, property = row.description.match(/INDEX ON :([^\(]+)\(([^\)]+)\)/)[1, 2]
{type: row.type.to_sym, label: label.to_sym, properties: [property.to_sym], state: row.state.to_sym}
end
end

def constraints(session)
result = query(session, 'CALL db.indexes()', {}, skip_instrumentation: true)

result.select { |row| row.type == 'node_unique_property' }.map do |row|
label, property = row.description.match(/INDEX ON :([^\(]+)\(([^\)]+)\)/)[1, 2]
{type: :uniqueness, label: label.to_sym, properties: [property.to_sym]}
end
end

def self.transaction_class
require 'neo4j/core/cypher_session/transactions/bolt'
Neo4j::Core::CypherSession::Transactions::Bolt
Expand Down
4 changes: 4 additions & 0 deletions lib/neo4j/core/cypher_session/adaptors/embedded.rb
Expand Up @@ -91,6 +91,10 @@ def connected?
" #{ANSI::BLUE}EMBEDDED CYPHER TRANSACTION:#{ANSI::CLEAR} #{ANSI::YELLOW}#{ms.round}ms#{ANSI::CLEAR}"
end

def default_subscribe
subscribe_to_transaction
end

private

def execution_results(queries)
Expand Down
4 changes: 4 additions & 0 deletions lib/neo4j/core/cypher_session/adaptors/http.rb
Expand Up @@ -102,6 +102,10 @@ def connected?
!!@requestor
end

def supports_metadata?
Gem::Version.new(version(nil)) >= Gem::Version.new('2.1.5')
end

# Basic wrapper around HTTP requests to standard Neo4j HTTP endpoints
# - Takes care of JSONifying objects passed as body (Hash/Array/Query)
# - Sets headers, including user agent string
Expand Down
34 changes: 34 additions & 0 deletions lib/neo4j/core/cypher_session/adaptors/schema.rb
@@ -0,0 +1,34 @@
module Neo4j
module Core
class CypherSession
module Adaptors
module Schema
def version(session)
result = query(session, 'CALL dbms.components()', {}, skip_instrumentation: true)

# BTW: community / enterprise could be retrieved via `result.first.edition`
result.first.versions[0]
end

def indexes(session)
result = query(session, 'CALL db.indexes()', {}, skip_instrumentation: true)

result.map do |row|
label, property = row.description.match(/INDEX ON :([^\(]+)\(([^\)]+)\)/)[1, 2]
{type: row.type.to_sym, label: label.to_sym, properties: [property.to_sym], state: row.state.to_sym}
end
end

def constraints(session)
result = query(session, 'CALL db.indexes()', {}, skip_instrumentation: true)

result.select { |row| row.type == 'node_unique_property' }.map do |row|
label, property = row.description.match(/INDEX ON :([^\(]+)\(([^\)]+)\)/)[1, 2]
{type: :uniqueness, label: label.to_sym, properties: [property.to_sym]}
end
end
end
end
end
end
end
3 changes: 2 additions & 1 deletion neo4j-core.gemspec
Expand Up @@ -18,8 +18,9 @@ Gem::Specification.new do |s|
Neo4j-core provides classes and methods to work with the graph database Neo4j.
DESCRIPTION

s.require_path = 'lib'
s.require_paths = %w[lib spec]
s.files = Dir.glob('{bin,lib,config}/**/*') + %w[README.md Gemfile neo4j-core.gemspec]
s.files += Dir['spec/neo4j/core/shared_examples/adaptor.rb', 'spec/neo4j_spec_helpers']
s.has_rdoc = true
s.extra_rdoc_files = %w[README.md]
s.rdoc_options = ['--quiet', '--title', 'Neo4j::Core', '--line-numbers', '--main', 'README.rdoc', '--inline-source']
Expand Down
7 changes: 7 additions & 0 deletions spec/neo4j/core/cypher_session/adaptors/bolt_spec.rb
Expand Up @@ -30,6 +30,13 @@
let_context(url: 'bolt://foo:bar@localhost:7687') { subject_should_not_raise }
end

describe '#default_subscribe' do
it 'makes the right subscription' do
expect(adaptor).to receive(:subscribe_to_request)
adaptor.default_subscribe
end
end

describe 'message in multiple chunks' do
before do
# This is standard response for INIT message, split into two chunks.
Expand Down
7 changes: 7 additions & 0 deletions spec/neo4j/core/cypher_session/adaptors/embedded_spec.rb
Expand Up @@ -23,6 +23,13 @@

let(:adaptor) { @adaptor }

describe '#default_subscribe' do
it 'makes the right subscription' do
expect(adaptor).to receive(:subscribe_to_transaction)
adaptor.default_subscribe
end
end

it_behaves_like 'Neo4j::Core::CypherSession::Adaptor'
end
end
12 changes: 12 additions & 0 deletions spec/neo4j/core/cypher_session/adaptors/http_spec.rb
Expand Up @@ -24,6 +24,18 @@
end
end

describe '#supports_metadata?' do
it 'supports in version 3.4.0' do
expect(adaptor).to receive(:version).and_return('3.4.0')
expect(adaptor.supports_metadata?).to be true
end

it 'does not supports in version 2.0.0' do
expect(adaptor).to receive(:version).and_return('2.0.0')
expect(adaptor.supports_metadata?).to be false
end
end

let(:session_double) { double('session', adaptor: subject) }

before do
Expand Down
15 changes: 5 additions & 10 deletions spec/neo4j/core/shared_examples/adaptor.rb
Expand Up @@ -29,13 +29,12 @@

expect(result[0].to_a[0].n).to be_a(Neo4j::Core::Node)
expect(result[1].to_a[0].n).to be_a(Neo4j::Core::Node)
# Maybe should have method like adaptor.returns_node_and_relationship_metadata?
if adaptor.is_a?(::Neo4j::Core::CypherSession::Adaptors::HTTP) && adaptor.version(session_double) < '2.1.5'
expect(result[0].to_a[0].n.labels).to eq(nil)
expect(result[1].to_a[0].n.labels).to eq(nil)
else
if adaptor.supports_metadata?
expect(result[0].to_a[0].n.labels).to eq([:Label1])
expect(result[1].to_a[0].n.labels).to eq([:Label2])
else
expect(result[0].to_a[0].n.labels).to eq(nil)
expect(result[1].to_a[0].n.labels).to eq(nil)
end
end

Expand All @@ -45,11 +44,7 @@
end

expect(result[0].to_a[0].n).to be_a(Neo4j::Core::Node)
if adaptor.is_a?(::Neo4j::Core::CypherSession::Adaptors::HTTP) && adaptor.version(session_double) < '2.1.5'
expect(result[0].to_a[0].n.labels).to eq(nil)
else
expect(result[0].to_a[0].n.labels).to eq([:Label1])
end
expect(result[0].to_a[0].n.labels).to eq(adaptor.supports_metadata? ? [:Label1] : nil)
end
end

Expand Down
32 changes: 32 additions & 0 deletions spec/neo4j_spec_helpers.rb
@@ -0,0 +1,32 @@
module Neo4jSpecHelpers
class << self
attr_accessor :expect_queries_count
end

self.expect_queries_count = 0

Neo4j::Core::CypherSession::Adaptors::Base.subscribe_to_query do |_message|
self.expect_queries_count += 1
end

def expect_queries(count)
start_count = Neo4jSpecHelpers.expect_queries_count
yield
expect(Neo4jSpecHelpers.expect_queries_count - start_count).to eq(count)
end

def delete_schema(session = nil)
Neo4j::Core::Label.drop_uniqueness_constraints_for(session || current_session)
Neo4j::Core::Label.drop_indexes_for(session || current_session)
end

def create_constraint(session, label_name, property, options = {})
label_object = Neo4j::Core::Label.new(label_name, session)
label_object.create_constraint(property, options)
end

def create_index(session, label_name, property, options = {})
label_object = Neo4j::Core::Label.new(label_name, session)
label_object.create_index(property, options)
end
end
46 changes: 2 additions & 44 deletions spec/spec_helper.rb
Expand Up @@ -48,6 +48,7 @@ def [](key)
require 'neo4j/core/cypher_session/adaptors/http'
require 'neo4j/core/cypher_session/adaptors/bolt'
require 'neo4j/core/cypher_session/adaptors/embedded'
require 'neo4j_spec_helpers'

module Neo4jSpecHelpers
# def log_queries!
Expand All @@ -62,17 +63,7 @@ def current_transaction
Neo4j::Transaction.current_for(Neo4j::Session.current)
end

class << self
attr_accessor :expect_queries_count
end

# rubocop:disable Style/GlobalVars
def expect_queries(count)
start_count = Neo4jSpecHelpers.expect_queries_count
yield
expect(Neo4jSpecHelpers.expect_queries_count - start_count).to eq(count)
end

def expect_http_requests(count)
start_count = $expect_http_request_count
yield
Expand All @@ -88,21 +79,6 @@ def setup_http_request_subscription
end
# rubocop:enable Style/GlobalVars

def delete_schema(session = nil)
Neo4j::Core::Label.drop_uniqueness_constraints_for(session || current_session)
Neo4j::Core::Label.drop_indexes_for(session || current_session)
end

def create_constraint(session, label_name, property, options = {})
label_object = Neo4j::Core::Label.new(label_name, session)
label_object.create_constraint(property, options)
end

def create_index(session, label_name, property, options = {})
label_object = Neo4j::Core::Label.new(label_name, session)
label_object.create_index(property, options)
end

def test_bolt_url
ENV['NEO4J_BOLT_URL']
end
Expand Down Expand Up @@ -145,27 +121,9 @@ def delete_db(session)
config.extend DRYSpec::Helpers
# config.include Helpers

config.before(:suite) do
# for expect_queries method
Neo4jSpecHelpers.expect_queries_count = 0

Neo4j::Core::CypherSession::Adaptors::Base.subscribe_to_query do |_message|
Neo4jSpecHelpers.expect_queries_count += 1
end
end

config.exclusion_filter = {
api: lambda do |ed|
RUBY_PLATFORM != 'java' && ed == :embedded
end,

server_only: lambda do |bool|
RUBY_PLATFORM == 'java' && bool
end,

bolt: lambda do
ENV['NEO4J_VERSION'].to_s.match(/^(community|enterprise)-2\./) ||
RUBY_ENGINE == 'jruby' # Because jruby doesn't implement sendmsg. Hopefully we can figure this out
ENV['NEO4J_VERSION'].to_s.match(/^(community|enterprise)-2\./)
end
}
end

0 comments on commit 7df2f69

Please sign in to comment.