From 62f6d76ff03c60d79405b594d271aadec4416347 Mon Sep 17 00:00:00 2001 From: maanav Date: Sun, 17 Jun 2018 19:36:36 +0530 Subject: [PATCH 1/4] Added documentation Added documentation in README for socketcluster-client-ruby --- README.md | 214 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 213 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2462846..b0dbc1c 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,214 @@ # socketcluster-client-ruby -Ruby client for socketcluster +A Ruby client for socketcluster.io + +Refer examples for more details : + +Overview +-------- +This client provides following functionality + +- Easy to setup and use +- Support for emitting and listening to remote events +- Automatic reconnection +- Pub/sub +- Authentication (JWT) +- Can be used for extensive unit-testing of all server side functions +- Support for ruby >= 2.2.0 + +To install use +```ruby + gem install socketclusterclient +``` + +Description +----------- +Create instance of `Socket` class by passing url of socketcluster-server end-point + +```ruby + # Create a socket instance + socket = ScClient.new('ws://localhost:8000/socketcluster/') +``` +**Important Note** : Default url to socketcluster end-point is always *ws://somedomainname.com/socketcluster/*. + +#### Registering basic listeners + +- Different functions are given as an argument to register listeners + +```ruby + require 'socketclusterclient' + require 'logger' + + logger = Logger.new(STDOUT) + logger.level = Logger::WARN + + on_connect = -> { logger.info('on connect got called') } + + on_disconnect = -> { logger.info('on disconnect got called') } + + on_connect_error = -> { logger.info('on connect error got called') } + + on_set_authentication = lambda do |socket, token| + logger.info("Token received #{token}") + socket.set_auth_token(token) + end + + on_authentication = lambda do |socket, is_authenticated| + logger.info("Authenticated is #{is_authenticated}") + end + + socket = ScClient.new('ws://localhost:8000/socketcluster/') + socket.set_basic_listener(on_connect, on_disconnect, on_connect_error) + socket.set_authentication_listener(on_set_authentication, on_authentication) + socket.connect +``` + +#### Connecting to server + +- For connecting to server + +```ruby + # This will send websocket handshake request to socketcluster-server + socket.connect +``` + +- By default reconnection to server is enabled, to configure delay for connection + +```ruby + # This will set automatic-reconnection to server with delay of 2 seconds and repeat it infinitely + socket.set_delay(2) + socket.connect +``` + +- To disable reconnection + +```ruby + # To disable reconnection + socket.set_reconnection(false) +``` + +Emitting and listening to events +-------------------------------- + +#### Event emitter + +- To emit a specified event on the corresponding socketcluster-server. The object sent can be String, Boolean, Long or JSONObject. + +```ruby + # Emit an event + socket.emit(event_name, message); + + socket.emit("chat", "Hi") +``` + +- To emit a specified event with acknowledgement on the corresponding socketcluster-server. The object sent can be String, Boolean, Long or JSONObject. + +```ruby + # Emit an event with acknowledgment + socket.emitack(event_name, message, ack_emit) + + socket.emitack('chat', 'Hello', ack_emit) + + ack_emit = lambda do |key, error, object| + puts "Got ack data => #{object} and error => #{error} and key => #{key}" + end +``` + +#### Event Listener + +- To listen an event from the corresponding socketcluster-server. The object received can be String, Boolean, Long or JSONObject. + +```ruby + # Receive an event + socket.on(event, message) + + socket.on('ping', message) + + message = lambda do |key, object| + puts "Got data => #{object} from key => #{key}" + end +``` + +- To listen an event from the corresponding socketcluster-server and send the acknowledgment back. The object received can be String, Boolean, Long or JSONObject. + +```ruby + # Receive an event and send the acknowledgement back + socket.onack(event, message_with_acknowledgment) + + socket.onack('ping', ack_message) + + ack_message = lambda do |key, object, block_ack_message| + puts "Got ack data => #{object} from key => #{key}" + block_ack_message.call('error lorem', 'data ipsum') + end +``` + +Implementing Pub-Sub via channels +--------------------------------- + +#### Creating channel + +- For creating and subscribing to channels: + +```ruby + # Subscribe to a channel + socket.subscribe('yell') + + # Subscribe to a channel with acknowledgement + socket.subscribeack('yell', ack_subscribe) + + ack_subscribe = lambda do |channel, error, _object| + puts "Subscribed successfully to channel => #{channel}" if error == '' + end +``` + +- For getting list of created channels : + +```ruby + # Get all subscribed channel + channels = socket.get_subscribed_channels +``` + +#### Publishing event on channel + +- For publishing event : + +```ruby + # Publish to a channel + socket.publish('yell', 'Hi') + + # Publish to a channel with acknowledgment + socket.publishack('yell', 'Hi', ack_publish) + + ack_publish = lambda do |channel, error, _object| + puts "Publish sent successfully to channel => #{channel}" if error == '' + end +``` + +#### Listening to channel + +- For listening to channel event : + +```ruby + # Listen to a channel + socket.onchannel('yell', channel_message) + + channel_message = lambda do |key, object| + puts "Got data => #{object} from key => #{key}" + end +``` + +#### Un-subscribing to channel + +- For unsubscribing to a channel + +```ruby + # Unsubscribe to a channel + socket.unsubscribe('yell') + + # Unsubscribe to a channel with acknowledgement + socket.unsubscribeack('yell', ack_unsubscribe) + + ack_unsubscribe = lambda do |channel, error, _object| + puts "Unsubscribed to channel => #{channel}" if error == '' + end +``` From 2161c4e0f29cb9d9b358778ab0924024b11929d0 Mon Sep 17 00:00:00 2001 From: maanav Date: Wed, 27 Jun 2018 20:58:47 +0530 Subject: [PATCH 2/4] Update project and test structure --- .rspec | 3 ++ .rspec_status | 4 ++ .simplecov | 3 ++ .travis.yml | 5 +++ Gemfile | 5 ++- Gemfile.lock | 54 +++++++++++++++++++++++++ README.md | 64 +++++++++++++++++++++++------- Rakefile | 6 +++ bin/console | 14 +++++++ bin/setup | 8 ++++ lib/socketclusterclient.rb | 4 +- lib/socketclusterclient/version.rb | 2 +- socketclusterclient.gemspec | 41 +++++++++++-------- spec/socketclusterclient_spec.rb | 9 +++++ spec/spec_helper.rb | 14 +++++++ 15 files changed, 202 insertions(+), 34 deletions(-) create mode 100644 .rspec create mode 100644 .rspec_status create mode 100644 .simplecov create mode 100644 .travis.yml create mode 100644 Gemfile.lock create mode 100644 Rakefile create mode 100755 bin/console create mode 100755 bin/setup create mode 100644 spec/socketclusterclient_spec.rb create mode 100644 spec/spec_helper.rb diff --git a/.rspec b/.rspec new file mode 100644 index 0000000..34c5164 --- /dev/null +++ b/.rspec @@ -0,0 +1,3 @@ +--format documentation +--color +--require spec_helper diff --git a/.rspec_status b/.rspec_status new file mode 100644 index 0000000..87c68e5 --- /dev/null +++ b/.rspec_status @@ -0,0 +1,4 @@ +example_id | status | run_time | +--------------------------------------- | ------ | --------------- | +./spec/socketclusterclient_spec.rb[1:1] | passed | 0.00071 seconds | +./spec/socketclusterclient_spec.rb[1:2] | failed | 0.01642 seconds | diff --git a/.simplecov b/.simplecov new file mode 100644 index 0000000..10b27b9 --- /dev/null +++ b/.simplecov @@ -0,0 +1,3 @@ +SimpleCov.start do + add_group "lib", "lib" +end diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..20e09ea --- /dev/null +++ b/.travis.yml @@ -0,0 +1,5 @@ +sudo: false +language: ruby +rvm: + - 2.3.3 +before_install: gem install bundler -v 1.16.1 diff --git a/Gemfile b/Gemfile index 2492017..4b9a750 100644 --- a/Gemfile +++ b/Gemfile @@ -1,5 +1,8 @@ -source "http://rubygems.org" +source "https://rubygems.org" +git_source(:github) {|repo_name| "https://github.com/opensocket" } + +# Specify your gem's dependencies in socketclusterclient.gemspec gemspec gem 'websocket-eventmachine-client' diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..9643d0e --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,54 @@ +PATH + remote: . + specs: + socketclusterclient (1.0.0) + websocket-eventmachine-client (~> 1.2) + +GEM + remote: https://rubygems.org/ + specs: + diff-lcs (1.3) + docile (1.3.1) + eventmachine (1.2.7) + json (2.1.0) + rake (10.5.0) + rspec (3.7.0) + rspec-core (~> 3.7.0) + rspec-expectations (~> 3.7.0) + rspec-mocks (~> 3.7.0) + rspec-core (3.7.1) + rspec-support (~> 3.7.0) + rspec-expectations (3.7.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.7.0) + rspec-mocks (3.7.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.7.0) + rspec-support (3.7.1) + simplecov (0.16.1) + docile (~> 1.1) + json (>= 1.8, < 3) + simplecov-html (~> 0.10.0) + simplecov-html (0.10.2) + websocket (1.2.8) + websocket-eventmachine-base (1.2.0) + eventmachine (~> 1.0) + websocket (~> 1.0) + websocket-native (~> 1.0) + websocket-eventmachine-client (1.2.0) + websocket-eventmachine-base (~> 1.0) + websocket-native (1.0.0) + +PLATFORMS + ruby + +DEPENDENCIES + bundler (~> 1.16) + rake (~> 10.0) + rspec (~> 3.0) + simplecov + socketclusterclient! + websocket-eventmachine-client + +BUNDLED WITH + 1.16.1 diff --git a/README.md b/README.md index b0dbc1c..7c6e940 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # socketcluster-client-ruby A Ruby client for socketcluster.io -Refer examples for more details : +Refer below examples for more details. Overview -------- @@ -15,11 +15,23 @@ This client provides following functionality - Can be used for extensive unit-testing of all server side functions - Support for ruby >= 2.2.0 -To install use +Installation +------------ + +Add this line to your application's Gemfile: + ```ruby - gem install socketclusterclient +gem 'socketclusterclient' ``` +And then execute: + + $ bundle + +Or install it yourself as: + + $ gem install socketclusterclient + Description ----------- Create instance of `Socket` class by passing url of socketcluster-server end-point @@ -71,18 +83,18 @@ Create instance of `Socket` class by passing url of socketcluster-server end-poi socket.connect ``` -- By default reconnection to server is enabled, to configure delay for connection +- By default reconnection to server is enabled, so to configure delay for connection ```ruby - # This will set automatic-reconnection to server with delay of 2 seconds and repeat it infinitely + # This will set automatic-reconnection to socketcluster-server with delay of 2 seconds and repeat it infinitely socket.set_delay(2) socket.connect ``` -- To disable reconnection +- For disabling reconnection to server ```ruby - # To disable reconnection + # This will disable reconnection to socketcluster-server socket.set_reconnection(false) ``` @@ -145,15 +157,15 @@ Emitting and listening to events Implementing Pub-Sub via channels --------------------------------- -#### Creating channel +#### Creating a channel -- For creating and subscribing to channels: +- For creating and subscribing to channels ```ruby - # Subscribe to a channel + # Subscribe to channel socket.subscribe('yell') - # Subscribe to a channel with acknowledgement + # Subscribe to channel with acknowledgement socket.subscribeack('yell', ack_subscribe) ack_subscribe = lambda do |channel, error, _object| @@ -161,16 +173,16 @@ Implementing Pub-Sub via channels end ``` -- For getting list of created channels : +- For getting list of created channels ```ruby # Get all subscribed channel channels = socket.get_subscribed_channels ``` -#### Publishing event on channel +#### Publishing an event on channel -- For publishing event : +- For publishing an event ```ruby # Publish to a channel @@ -186,7 +198,7 @@ Implementing Pub-Sub via channels #### Listening to channel -- For listening to channel event : +- For listening to a channel event ```ruby # Listen to a channel @@ -212,3 +224,25 @@ Implementing Pub-Sub via channels puts "Unsubscribed to channel => #{channel}" if error == '' end ``` + +Usage +----- + +TODO: Write usage instructions here + +Development +----------- + +After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. + +To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). + +Contributing +------------ + +Bug reports and pull requests are welcome on GitHub at https://github.com/opensocket/socketcluster-client-ruby. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct. + +License +------- + +The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..b7e9ed5 --- /dev/null +++ b/Rakefile @@ -0,0 +1,6 @@ +require "bundler/gem_tasks" +require "rspec/core/rake_task" + +RSpec::Core::RakeTask.new(:spec) + +task :default => :spec diff --git a/bin/console b/bin/console new file mode 100755 index 0000000..478e256 --- /dev/null +++ b/bin/console @@ -0,0 +1,14 @@ +#!/usr/bin/env ruby + +require "bundler/setup" +require "socketclusterclient" + +# You can add fixtures and/or initialization code here to make experimenting +# with your gem easier. You can also use a different console, if you like. + +# (If you use this, don't forget to add pry to your Gemfile!) +# require "pry" +# Pry.start + +require "irb" +IRB.start(__FILE__) diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..dce67d8 --- /dev/null +++ b/bin/setup @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +IFS=$'\n\t' +set -vx + +bundle install + +# Do any other automated setup that you need to do here diff --git a/lib/socketclusterclient.rb b/lib/socketclusterclient.rb index 2430db6..5feb307 100644 --- a/lib/socketclusterclient.rb +++ b/lib/socketclusterclient.rb @@ -1,3 +1,5 @@ +require 'socketclusterclient/version' + require_relative './sc_client' # @@ -5,5 +7,5 @@ # # @author Maanav Shah # -module SocketclusterClient +module Socketclusterclient end diff --git a/lib/socketclusterclient/version.rb b/lib/socketclusterclient/version.rb index ff08a80..279a8cb 100644 --- a/lib/socketclusterclient/version.rb +++ b/lib/socketclusterclient/version.rb @@ -1,3 +1,3 @@ -module SocketClusterClient +module Socketclusterclient VERSION = '1.0.0'.freeze end diff --git a/socketclusterclient.gemspec b/socketclusterclient.gemspec index 8654acb..c6ee9b5 100644 --- a/socketclusterclient.gemspec +++ b/socketclusterclient.gemspec @@ -1,23 +1,32 @@ -require 'rake' -$LOAD_PATH.push File.expand_path('lib', __dir__) +lib = File.expand_path("../lib", __FILE__) +$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'socketclusterclient/version' -Gem::Specification.new do |s| - s.name = 'socketclusterclient' - s.version = SocketClusterClient::VERSION - s.platform = Gem::Platform::RUBY - s.licenses = ['MIT'] - s.summary = 'Ruby client for socketcluster' - s.homepage = 'https://socketcluster.io/' - s.description = 'A socketcluster client designed in ruby' - s.email = %w[shahmaanav07@gmail.com piyushwww13@gmail.com sachinshinde7676@gmail.com] - s.authors = ['Maanav Shah', 'Piyush Wani', 'Sachin Shinde'] +Gem::Specification.new do |spec| + spec.name = 'socketclusterclient' + spec.version = Socketclusterclient::VERSION + spec.platform = Gem::Platform::RUBY + spec.licenses = ['MIT'] + spec.summary = 'Ruby client for socketcluster' + spec.homepage = 'https://socketcluster.io/' + spec.description = 'A socketcluster client designed in ruby' + spec.email = %w[shahmaanav07@gmail.com piyushwww13@gmail.com sachinshinde7676@gmail.com] + spec.authors = ['Maanav Shah', 'Piyush Wani', 'Sachin Shinde'] - s.files = Rake::FileList['lib/**/*.rb'] - s.require_paths = ['lib'] + spec.files = `git ls-files -z`.split("\x0").reject do |f| + f.match(%r{^(test|spec|features)/}) + end + spec.bindir = "exe" + spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } + spec.require_paths = ["lib"] - s.required_ruby_version = '>= 2.2.0' + spec.required_ruby_version = '>= 2.2.0' + + spec.add_development_dependency "bundler", "~> 1.16" + spec.add_development_dependency "rake", "~> 10.0" + spec.add_development_dependency "rspec", "~> 3.0" + spec.add_development_dependency "simplecov" + spec.add_dependency('websocket-eventmachine-client', '~> 1.2') - s.add_dependency('websocket-eventmachine-client', '~> 1.2') end diff --git a/spec/socketclusterclient_spec.rb b/spec/socketclusterclient_spec.rb new file mode 100644 index 0000000..5a80384 --- /dev/null +++ b/spec/socketclusterclient_spec.rb @@ -0,0 +1,9 @@ +RSpec.describe Socketclusterclient do + it "has a version number" do + expect(Socketclusterclient::VERSION).not_to be nil + end + + it "does something useful" do + expect(false).to eq(true) + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..8145adf --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,14 @@ +require "bundler/setup" +require "socketclusterclient" + +RSpec.configure do |config| + # Enable flags like --only-failures and --next-failure + config.example_status_persistence_file_path = ".rspec_status" + + # Disable RSpec exposing methods globally on `Module` and `main` + config.disable_monkey_patching! + + config.expect_with :rspec do |c| + c.syntax = :expect + end +end From 2687fffd1355eb611763b9fcd0f29e92eb8ae848 Mon Sep 17 00:00:00 2001 From: maanav Date: Sat, 7 Jul 2018 12:00:40 +0530 Subject: [PATCH 3/4] Minor fix for rspec --- .rspec | 2 -- .rspec_status | 4 ---- .simplecov | 2 +- spec/socketclusterclient_spec.rb | 6 +----- 4 files changed, 2 insertions(+), 12 deletions(-) delete mode 100644 .rspec_status diff --git a/.rspec b/.rspec index 34c5164..4e1e0d2 100644 --- a/.rspec +++ b/.rspec @@ -1,3 +1 @@ ---format documentation --color ---require spec_helper diff --git a/.rspec_status b/.rspec_status deleted file mode 100644 index 87c68e5..0000000 --- a/.rspec_status +++ /dev/null @@ -1,4 +0,0 @@ -example_id | status | run_time | ---------------------------------------- | ------ | --------------- | -./spec/socketclusterclient_spec.rb[1:1] | passed | 0.00071 seconds | -./spec/socketclusterclient_spec.rb[1:2] | failed | 0.01642 seconds | diff --git a/.simplecov b/.simplecov index 10b27b9..a9a18fd 100644 --- a/.simplecov +++ b/.simplecov @@ -1,3 +1,3 @@ SimpleCov.start do - add_group "lib", "lib" + add_group 'lib', 'lib' end diff --git a/spec/socketclusterclient_spec.rb b/spec/socketclusterclient_spec.rb index 5a80384..75ad1d4 100644 --- a/spec/socketclusterclient_spec.rb +++ b/spec/socketclusterclient_spec.rb @@ -1,9 +1,5 @@ RSpec.describe Socketclusterclient do - it "has a version number" do + it 'has a version number' do expect(Socketclusterclient::VERSION).not_to be nil end - - it "does something useful" do - expect(false).to eq(true) - end end From 71b30b232cca2239a565161d9798da8e7392b9b4 Mon Sep 17 00:00:00 2001 From: maanav Date: Sat, 7 Jul 2018 12:11:01 +0530 Subject: [PATCH 4/4] Add unit test for lib Added unit test for data_models, emitter, parser and sc_client --- spec/lib/data_models_spec.rb | 164 +++++++++++++++++++++++++++++++++++ spec/lib/emitter_spec.rb | 139 +++++++++++++++++++++++++++++ spec/lib/parser_spec.rb | 72 +++++++++++++++ spec/lib/sc_client_spec.rb | 119 +++++++++++++++++++++++++ 4 files changed, 494 insertions(+) create mode 100644 spec/lib/data_models_spec.rb create mode 100644 spec/lib/emitter_spec.rb create mode 100644 spec/lib/parser_spec.rb create mode 100644 spec/lib/sc_client_spec.rb diff --git a/spec/lib/data_models_spec.rb b/spec/lib/data_models_spec.rb new file mode 100644 index 0000000..90ba847 --- /dev/null +++ b/spec/lib/data_models_spec.rb @@ -0,0 +1,164 @@ +require 'spec_helper' + +RSpec.describe DataModels do + include DataModels + + describe 'data_models' do + context 'get_ack_object' do + let(:error) { 'error' } + let(:data) { { key: 'value' } } + let(:cid) { [*1..6].sample } + + before(:each) do + @ack_object = get_ack_object(error, data, cid) + end + + it 'should return an ack object of type hash' do + expect(@ack_object.class).to eq(Hash) + end + + it 'should return an error, data and cid in ack object' do + expect(@ack_object.keys.include?(:error)).to be(true) + expect(@ack_object[:error]).to eq(error) + expect(@ack_object.keys.include?(:data)).to be(true) + expect(@ack_object[:data]).to eq(data) + expect(@ack_object.keys.include?(:cid)).to be(true) + expect(@ack_object[:cid]).to eq(cid) + end + end + + context 'get_emit_object' do + let(:event) { 'event' } + let(:data) { { key: 'value' } } + + before(:each) do + @emit_object = get_emit_object(event, data) + end + + it 'should return an emit object of type hash' do + expect(@emit_object.class).to eq(Hash) + end + + it 'should return an event and data in emit object' do + expect(@emit_object.keys.include?(:event)).to be(true) + expect(@emit_object[:event]).to eq(event) + expect(@emit_object.keys.include?(:data)).to be(true) + expect(@emit_object[:data]).to eq(data) + end + end + + context 'get_emit_ack_object' do + let(:event) { 'event' } + let(:data) { { key: 'value' } } + let(:cid) { [*1..6].sample } + + before(:each) do + @emit_ack_object = get_emit_ack_object(event, data, cid) + end + + it 'should return an emit ack object of type hash' do + expect(@emit_ack_object.class).to eq(Hash) + end + + it 'should return an event, data and cid in emit ack object' do + expect(@emit_ack_object.keys.include?(:event)).to be(true) + expect(@emit_ack_object[:event]).to eq(event) + expect(@emit_ack_object.keys.include?(:data)).to be(true) + expect(@emit_ack_object[:data]).to eq(data) + expect(@emit_ack_object.keys.include?(:cid)).to be(true) + expect(@emit_ack_object[:cid]).to eq(cid) + end + end + + context 'get_handshake_object' do + let(:cid) { [*1..6].sample } + + before(:each) do + @handshake_object = get_handshake_object(cid) + end + + it 'should return a handshake object of type hash' do + expect(@handshake_object.class).to eq(Hash) + end + + it 'should return an event, data and cid in handshake object' do + expect(@handshake_object.keys.include?(:event)).to be(true) + expect(@handshake_object[:event]).to eq('#handshake') + expect(@handshake_object.keys.include?(:data)).to be(true) + expect(@handshake_object[:data].keys.include?(:authToken)).to be(true) + expect(@handshake_object.keys.include?(:cid)).to be(true) + expect(@handshake_object[:cid]).to eq(cid) + end + end + + context 'get_publish_object' do + let(:channel) { 'channel' } + let(:data) { { key: 'value' } } + let(:cid) { [*1..6].sample } + + before(:each) do + @publish_object = get_publish_object(channel, data, cid) + end + + it 'should return a publish object of type hash' do + expect(@publish_object.class).to eq(Hash) + end + + it 'should return an event, channel, data and cid in publish object' do + expect(@publish_object.keys.include?(:event)).to be(true) + expect(@publish_object[:event]).to eq('#publish') + expect(@publish_object.keys.include?(:data)).to be(true) + expect(@publish_object[:data].keys.include?(:channel)).to be(true) + expect(@publish_object[:data].class).to eq(Hash) + expect(@publish_object.keys.include?(:cid)).to be(true) + expect(@publish_object[:cid]).to be(cid) + end + end + + context 'get_subscribe_object' do + let(:channel) { 'channel' } + let(:cid) { [*1..6].sample } + + before(:each) do + @subscribe_object = get_subscribe_object(channel, cid) + end + + it 'should return a subscribe object of type hash' do + expect(@subscribe_object.class).to eq(Hash) + end + + it 'should return an event, data, channel and cid in subscribe object' do + expect(@subscribe_object.keys.include?(:event)).to be(true) + expect(@subscribe_object[:event]).to eq('#subscribe') + expect(@subscribe_object[:data].class).to eq(Hash) + expect(@subscribe_object.keys.include?(:data)).to be(true) + expect(@subscribe_object[:data].keys.include?(:channel)).to be(true) + expect(@subscribe_object[:data][:channel]).to eq(channel) + expect(@subscribe_object.keys.include?(:cid)).to be(true) + expect(@subscribe_object[:cid]).to be(cid) + end + end + + context 'get_unsubscribe_object' do + let(:channel) { 'channel' } + let(:cid) { [*1..6].sample } + + before(:each) do + @unsubscribe_object = get_unsubscribe_object(channel, cid) + end + + it 'should return an unsubscribe object of type hash' do + expect(@unsubscribe_object.class).to eq(Hash) + end + + it 'should return an event, data and cid in unsubscribe object' do + expect(@unsubscribe_object.keys.include?(:event)).to be(true) + expect(@unsubscribe_object[:event]).to eq('#unsubscribe') + expect(@unsubscribe_object.keys.include?(:data)).to be(true) + expect(@unsubscribe_object[:data]).to eq(channel) + expect(@unsubscribe_object.keys.include?(:cid)).to be(true) + expect(@unsubscribe_object[:cid]).to be(cid) + end + end + end +end diff --git a/spec/lib/emitter_spec.rb b/spec/lib/emitter_spec.rb new file mode 100644 index 0000000..0077b16 --- /dev/null +++ b/spec/lib/emitter_spec.rb @@ -0,0 +1,139 @@ +require 'spec_helper' + +RSpec.describe Emitter do + include Emitter + + describe 'emitter' do + context 'initialize_emitter' do + it 'should not have instance variables' do + expect(@events).to eq(nil) + expect(@events_ack).to eq(nil) + end + + it 'should initialize instance variables' do + initialize_emitter + + expect(@events).to_not eq(nil) + expect(@events_ack).to_not eq(nil) + expect(@events.class).to eq(Hash) + expect(@events_ack.class).to eq(Hash) + end + end + + context 'on' do + before(:each) do + initialize_emitter + end + + let(:key) { 'ping' } + let(:message) { ->(key, object) { "#{key} #{object}" } } + + it 'should not have an event with key' do + expect(@events[key]).to eq(nil) + end + + it 'should have an event with key' do + on(key, message) + + expect(@events[key]).to be(message) + end + end + + context 'onchannel' do + before(:each) do + initialize_emitter + end + + let(:key) { 'ping' } + let(:message) { ->(key, object) { "#{key} #{object}" } } + + it 'should not have an event with key' do + expect(@events[key]).to eq(nil) + end + + it 'should have an event with key' do + onchannel(key, message) + + expect(@events[key]).to be(message) + end + end + + context 'onack' do + before(:each) do + initialize_emitter + end + + let(:key) { 'ping' } + let(:message) { ->(key, object, ack_block) { ack_block.call(key, object) } } + let(:ack_message) { ->(key, object) { "#{key} #{object}" } } + + it 'should not have an acknowledgement event with key' do + expect(@events_ack[key]).to eq(nil) + end + + it 'should have an acknowledgement event with key' do + onack(key, ack_message) + + expect(@events_ack[key]).to be(ack_message) + end + end + + context 'execute' do + before(:each) do + initialize_emitter + end + + let(:key) { 'ping' } + let(:message) { ->(key, object) { "#{key} #{object}" } } + + it 'should not have an event with key' do + expect(@events[key]).to eq(nil) + end + + it 'should execute event' do + on(key, message) + + expect(execute(key, 'pong')).to eq('ping pong') + end + end + + context 'haseventack' do + before(:each) do + initialize_emitter + end + + let(:key) { 'ping' } + let(:message) { ->(key, object) { "#{key} #{object}" } } + + it 'should not have an event with key' do + expect(@events_ack[key]).to eq(nil) + end + + it 'should return an acknowledgment event from key' do + onack(key, message) + + expect(haseventack(key)).to eq(message) + end + end + + context 'onack' do + before(:each) do + initialize_emitter + end + + let(:key) { 'ping' } + let(:message) { ->(key, object, ack_block) { ack_block.call(key, object) } } + let(:ack_message) { ->(key, object) { "#{key} #{object}" } } + + it 'should not have an event with key' do + expect(@events_ack[key]).to eq(nil) + end + + it 'should expect an acknowledgment event from key' do + onack(key, message) + + expect(executeack(key, 'pong', ack_message)).to eq('ping pong') + end + end + end +end diff --git a/spec/lib/parser_spec.rb b/spec/lib/parser_spec.rb new file mode 100644 index 0000000..5505ae8 --- /dev/null +++ b/spec/lib/parser_spec.rb @@ -0,0 +1,72 @@ +require 'spec_helper' + +RSpec.describe Parser do + CHECK_AUTHENTICATION = 1 + PUBLISH = 2 + REMOVE_AUTHENTICATION = 3 + SET_AUTHENTICATION = 4 + EVENT = 5 + ACKNOWLEDGEMENT = 6 + + describe 'parser' + describe 'parse' + context 'check authentication' do + let(:event) { '' } + let(:response_id) { 1 } + + it 'should check if client is authenticated' do + result = Parser.parse(event, response_id) + expect(result).to eq(CHECK_AUTHENTICATION) + end + end + + context 'publish' do + let(:event) { '#publish' } + let(:response_id) { [*1..6].sample } + + it 'should check if event is publish' do + result = Parser.parse(event, response_id) + expect(result).to eq(PUBLISH) + end + end + + context 'remove authentication token' do + let(:event) { '#removeAuthToken' } + let(:response_id) { [*1..6].sample } + + it 'should remove authentication token' do + result = Parser.parse(event, response_id) + expect(result).to eq(REMOVE_AUTHENTICATION) + end + end + + context 'set authentication' do + let(:event) { '#setAuthToken' } + let(:response_id) { [*1..6].sample } + + it 'should set authentication token' do + result = Parser.parse(event, response_id) + expect(result).to eq(SET_AUTHENTICATION) + end + end + + context 'random event' do + let(:event) { '#event' } + let(:response_id) { [*1..6].sample } + + it 'should check if event is publish' do + result = Parser.parse(event, response_id) + expect(result).to eq(EVENT) + end + end + + context 'acknowledgment' do + let(:event) { '' } + let(:response_id) { 6 } + + it 'should acknowledge the event' do + result = Parser.parse(event, response_id) + expect(result).to eq(ACKNOWLEDGEMENT) + end + end +end diff --git a/spec/lib/sc_client_spec.rb b/spec/lib/sc_client_spec.rb new file mode 100644 index 0000000..d329f1b --- /dev/null +++ b/spec/lib/sc_client_spec.rb @@ -0,0 +1,119 @@ +require 'spec_helper' + +RSpec.describe Socketclusterclient do + include Socketclusterclient + + describe 'socketcluster client' do + before(:each) do + @connect_url = 'ws://localhost:8000/socketcluster/' + @socket = ScClient.new(@connect_url) + end + + describe 'initialize' do + context 'instance variables' do + it 'should initialize all instance variables' do + expect(@socket.instance_variable_get(:@id)).to eq('') + expect(@socket.instance_variable_get(:@cnt)).to eq(0) + expect(@socket.instance_variable_get(:@acks)).to eq({}) + expect(@socket.instance_variable_get(:@channels)).to eq([]) + expect(@socket.instance_variable_get(:@enable_reconnection)).to eq(true) + expect(@socket.instance_variable_get(:@delay)).to eq(3) + end + + it 'should assign connect_url to instance variable @url' do + expect(@socket.instance_variable_get(:@url)).to eq(@connect_url) + end + end + end + + describe 'set_basic_listener' do + let(:on_connect) { -> { puts 'on connect got called' } } + let(:on_disconnect) { -> { puts 'on connect got called' } } + let(:on_connect_error) { -> { puts 'on connect got called' } } + + before(:each) do + @socket.set_basic_listener(on_connect, on_disconnect, on_connect_error) + end + + context 'set connect, disconnect and error listeners' do + it 'should have on_connected, on_disconnected and on_connect_error listeners' do + expect(@socket.instance_variable_get(:@on_connected)).to eq(on_connect) + expect(@socket.instance_variable_get(:@on_disconnected)).to eq(on_disconnect) + expect(@socket.instance_variable_get(:@on_connect_error)).to eq(on_connect_error) + end + end + end + + describe 'set_authentication_listener' do + let(:on_set_authentication) { ->(_socket, token) { @socket.set_auth_token(token) } } + let(:on_authentication) { ->(_socket, is_authenticated) { puts "Authenticated is #{is_authenticated}" } } + + before(:each) do + @socket.set_authentication_listener(on_set_authentication, on_authentication) + end + + context 'set on_set_authentication and on_authentication listeners' do + it 'should have on_set_authentication and on_authentication listeners' do + expect(@socket.instance_variable_get(:@on_set_authentication)).to eq(on_set_authentication) + expect(@socket.instance_variable_get(:@on_authentication)).to eq(on_authentication) + end + end + end + + describe 'set_auth_token' do + let(:token) { 1_234_567_890 } + + before(:each) do + @socket.set_auth_token(token) + end + + context 'set authentication token' do + it 'should have authentication token' do + expect(@socket.instance_variable_get(:@auth_token)).to eq(token.to_s) + end + end + end + + describe 'get_subscribed_channels' do + let(:channels) { %w[channel1 channel2] } + + before(:each) do + @socket.instance_variable_set(:@channels, channels) + end + + context 'should provide subscribed channels' do + it 'should provide list of all subscribed channels' do + expect(@socket.get_subscribed_channels).to eq(channels) + end + end + end + + describe 'set_delay' do + let(:delay) { 5 } + + before(:each) do + @socket.set_delay(delay) + end + + context 'should set delay' do + it 'should set delay to assigned value' do + expect(@socket.instance_variable_get(:@delay)).to eq(delay) + end + end + end + + describe 'set_reconnection' do + let(:reconnect) { true } + + before(:each) do + @socket.set_reconnection(reconnect) + end + + context 'should set reconnection strategy' do + it 'should set to enable reconnection to assigned value' do + expect(@socket.instance_variable_get(:@enable_reconnection)).to eq(reconnect) + end + end + end + end +end