diff --git a/CHANGELOG.md b/CHANGELOG.md index 82a1eb3..88c6530 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Change Log This project adheres to [Semantic Versioning](http://semver.org/). -# 0.1 +## 0.2 +* Core Logux facilities are moved to `logux-rack` gem. +* `Logux::Actions` is soft-deprecated. Please use `Logux::Action` from now on. +* `Logux::Model::UpdatesDeprecator` is now coupled with `Logux::ActionCaller` via Logux configuration. + +## 0.1.1 +* Rails 6.0 support. + +## 0.1 * Initial release. diff --git a/Gemfile b/Gemfile index 0285624..71d2ab1 100644 --- a/Gemfile +++ b/Gemfile @@ -6,3 +6,6 @@ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" } # Specify your gem's dependencies in logux_rails.gemspec gemspec + +# NOTE: Remove this line after logux-rack is released on rubygems +gem 'logux-rack', github: 'logux/logux-rack' diff --git a/README.md b/README.md index 1a2010c..98a14ee 100644 --- a/README.md +++ b/README.md @@ -30,17 +30,22 @@ Logux.configuration do |config| end ``` -Mount logux in routes: +Mount `Logux::Rack` in your application routing configuration: ```ruby +# config/routes.rb +Rails.application.routes.draw do mount Logux::Engine => '/' +end ``` After this, POST requests to `/logux` will be processed by `LoguxController`. You can redefine it or inherit from, if it necessary, for example, for implementing custom authorization flow. Logux Rails will try to find Action for the specific message from Logux Server. For example, for `project/rename` action, you should define `Action::Project` class, inherited from `Logux::Action` base class, and implement `rename` method. -You can execute `rake logux:actions` to get the list of available action types, or `rake logux:channels` to get the list of available channels. +### Rake commands + +Use `rails logux:actions` command to get the list of available action types, or `rails logux:channels` for channels. The default search path is set to `app/logux/actions` and `app/logux/channels` for actions and channels correspondingly, assuming `app` directory is the root of your Rails application. Both command support custom search paths: `rails logux:actions[lib/logux/actions]`. ## Development with Docker diff --git a/app/controllers/logux_controller.rb b/app/controllers/logux_controller.rb deleted file mode 100644 index e1036d9..0000000 --- a/app/controllers/logux_controller.rb +++ /dev/null @@ -1,41 +0,0 @@ -# frozen_string_literal: true - -class LoguxController < ActionController::Base - include ActionController::Live - - def create - logux_stream.write('[') - Logux.verify_request_meta_data(meta_params) - Logux.process_batch(stream: logux_stream, batch: command_params) - rescue => ex - handle_processing_errors(ex) - ensure - logux_stream.write(']') - logux_stream.close - end - - private - - def unsafe_params - params.to_unsafe_h - end - - def command_params - unsafe_params.dig('commands') - end - - def meta_params - unsafe_params&.slice(:version, :password) - end - - def logux_stream - @logux_stream ||= Logux::Stream.new(response.stream) - end - - def handle_processing_errors(exception) - Logux.configuration.on_error.call(exception) - Logux.logger.error("#{exception}\n#{exception.backtrace.join("\n")}") - ensure - logux_stream.write(Logux::ErrorRenderer.new(exception).message) - end -end diff --git a/app/helpers/logux_helper.rb b/app/helpers/logux_helper.rb index 98f8bd3..138d020 100644 --- a/app/helpers/logux_helper.rb +++ b/app/helpers/logux_helper.rb @@ -1,4 +1,3 @@ # frozen_string_literal: true -module LoguxHelper -end +module LoguxHelper; end diff --git a/config/routes.rb b/config/routes.rb index ae9e54b..a761b36 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true Logux::Engine.routes.draw do - resource :logux, only: %i[create], controller: :logux + mount Logux::Rack::App => '/' end diff --git a/lib/logux.rb b/lib/logux.rb deleted file mode 100644 index c044350..0000000 --- a/lib/logux.rb +++ /dev/null @@ -1,107 +0,0 @@ -# frozen_string_literal: true - -require 'configurations' -require 'rest-client' -require 'rails/engine' -require 'active_support' -require 'action_controller' -require 'logux/engine' -require 'nanoid' -require 'colorize' - -module Logux - extend ActiveSupport::Autoload - include Configurations - - PROTOCOL_VERSION = 1 - - class WithMetaError < StandardError - attr_reader :meta - - def initialize(msg, meta: nil) - @meta = meta - super(msg) - end - end - - UnknownActionError = Class.new(WithMetaError) - UnknownChannelError = Class.new(WithMetaError) - UnauthorizedError = Class.new(StandardError) - - autoload :Client, 'logux/client' - autoload :Meta, 'logux/meta' - autoload :Actions, 'logux/actions' - autoload :Auth, 'logux/auth' - autoload :BaseController, 'logux/base_controller' - autoload :ActionController, 'logux/action_controller' - autoload :ChannelController, 'logux/channel_controller' - autoload :ClassFinder, 'logux/class_finder' - autoload :ActionCaller, 'logux/action_caller' - autoload :PolicyCaller, 'logux/policy_caller' - autoload :Policy, 'logux/policy' - autoload :Add, 'logux/add' - autoload :Node, 'logux/node' - autoload :Response, 'logux/response' - autoload :Stream, 'logux/stream' - autoload :Process, 'logux/process' - autoload :Logger, 'logux/logger' - autoload :Version, 'logux/version' - autoload :Test, 'logux/test' - autoload :ErrorRenderer, 'logux/error_renderer' - autoload :Model, 'logux/model' - - configurable :logux_host, :verify_authorized, - :password, :logger, - :on_error, :auth_rule, - :render_backtrace_on_error - - configuration_defaults do |config| - config.logux_host = 'localhost:1338' - config.verify_authorized = true - config.logger = ActiveSupport::Logger.new(STDOUT) - if defined?(Rails) && Rails.respond_to?(:logger) - config.logger = Rails.logger - end - config.on_error = proc {} - config.auth_rule = proc { false } - config.render_backtrace_on_error = true - end - - def self.add(action, meta = Meta.new) - Logux::Add.new.call([[action, meta]]) - end - - def self.add_batch(commands) - Logux::Add.new.call(commands) - end - - def self.undo(meta, reason: nil, data: {}) - add( - data.merge(type: 'logux/undo', id: meta.id, reason: reason), - Logux::Meta.new(clients: [meta.client_id]) - ) - end - - def self.verify_request_meta_data(meta_params) - if Logux.configuration.password.nil? - logger.warn(%(Please, add password for logux server: - Logux.configure do |c| - c.password = 'your-password' - end)) - end - auth = Logux.configuration.password == meta_params&.dig(:password) - raise Logux::UnauthorizedError, 'Incorrect password' unless auth - end - - def self.process_batch(stream:, batch:) - Logux::Process::Batch.new(stream: stream, batch: batch).call - end - - def self.generate_action_id - Logux::Node.instance.generate_action_id - end - - def self.logger - configuration.logger - end -end diff --git a/lib/logux/actions.rb b/lib/logux/action.rb similarity index 88% rename from lib/logux/actions.rb rename to lib/logux/action.rb index 69a6bb4..844cb3d 100644 --- a/lib/logux/actions.rb +++ b/lib/logux/action.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module Logux - class Actions < ::ActionController::Parameters + class Action < ::ActionController::Parameters def action_name type&.split('/')&.dig(0) end diff --git a/lib/logux/action_caller.rb b/lib/logux/action_caller.rb deleted file mode 100644 index 5dc5a4e..0000000 --- a/lib/logux/action_caller.rb +++ /dev/null @@ -1,42 +0,0 @@ -# frozen_string_literal: true - -module Logux - class ActionCaller - attr_reader :action, :meta - - delegate :logger, to: :Logux - - def initialize(action:, meta:) - @action = action - @meta = meta - end - - def call! - Logux::Model::UpdatesDeprecator.watch(level: :error) do - logger.debug( - "Searching action for Logux action: #{action}, meta: #{meta}" - ) - format(action_controller.public_send(action.action_type)) - end - rescue Logux::UnknownActionError, Logux::UnknownChannelError => e - logger.warn(e) - format(nil) - end - - private - - def format(response) - return response if response.is_a?(Logux::Response) - - Logux::Response.new(:processed, action: action, meta: meta) - end - - def class_finder - @class_finder ||= Logux::ClassFinder.new(action: action, meta: meta) - end - - def action_controller - class_finder.find_action_class.new(action: action, meta: meta) - end - end -end diff --git a/lib/logux/action_controller.rb b/lib/logux/action_controller.rb deleted file mode 100644 index 70d9610..0000000 --- a/lib/logux/action_controller.rb +++ /dev/null @@ -1,6 +0,0 @@ -# frozen_string_literal: true - -module Logux - class ActionController < Logux::BaseController - end -end diff --git a/lib/logux/add.rb b/lib/logux/add.rb deleted file mode 100644 index 5f0d724..0000000 --- a/lib/logux/add.rb +++ /dev/null @@ -1,37 +0,0 @@ -# frozen_string_literal: true - -module Logux - class Add - attr_reader :client, :version, :password - - def initialize(client: Logux::Client.new, - version: Logux::PROTOCOL_VERSION, - password: Logux.configuration.password) - @client = client - @version = version - @password = password - end - - def call(commands) - return if commands.empty? - - prepared_data = prepare_data(commands) - Logux.logger.debug("Logux add: #{prepared_data}") - client.post(prepared_data) - end - - private - - def prepare_data(commands) - { - version: PROTOCOL_VERSION, - password: password, - commands: commands.map do |command| - action = command.first - meta = command[1] - ['action', action, meta || Meta.new] - end - } - end - end -end diff --git a/lib/logux/auth.rb b/lib/logux/auth.rb deleted file mode 100644 index 988f2d0..0000000 --- a/lib/logux/auth.rb +++ /dev/null @@ -1,6 +0,0 @@ -# frozen_string_literal: true - -module Logux - class Auth < Hashie::Mash - end -end diff --git a/lib/logux/base_controller.rb b/lib/logux/base_controller.rb deleted file mode 100644 index a042184..0000000 --- a/lib/logux/base_controller.rb +++ /dev/null @@ -1,37 +0,0 @@ -# frozen_string_literal: true - -module Logux - class BaseController - class << self - def verify_authorized! - Logux.configuration.verify_authorized = true - end - - def unverify_authorized! - Logux.configuration.verify_authorized = false - end - end - - attr_reader :action, :meta - - def initialize(action:, meta: {}) - @action = action - @meta = meta - end - - def respond(status, action: @action, meta: @meta, custom_data: nil) - Logux::Response.new(status, - action: action, - meta: meta, - custom_data: custom_data) - end - - def user_id - @user_id ||= meta.user_id - end - - def node_id - @node_id ||= meta.node_id - end - end -end diff --git a/lib/logux/channel_controller.rb b/lib/logux/channel_controller.rb deleted file mode 100644 index 8975ecc..0000000 --- a/lib/logux/channel_controller.rb +++ /dev/null @@ -1,24 +0,0 @@ -# frozen_string_literal: true - -module Logux - class ChannelController < BaseController - def subscribe - Logux.add_batch(initial_data.map { |d| [d, initial_meta] }) - end - - def initial_data - [] - end - - def initial_meta - { clients: [meta.client_id] } - end - - def since_time - @since_time ||= begin - since = action['since'].try(:[], 'time') - Time.at(since).to_datetime if since - end - end - end -end diff --git a/lib/logux/class_finder.rb b/lib/logux/class_finder.rb deleted file mode 100644 index f9070bb..0000000 --- a/lib/logux/class_finder.rb +++ /dev/null @@ -1,61 +0,0 @@ -# frozen_string_literal: true - -module Logux - class ClassFinder - attr_reader :action, :meta - - def initialize(action:, meta:) - @action = action - @meta = meta - end - - def find_action_class - "#{class_namespace}::#{class_name}".constantize - rescue NameError - message = - "Unable to find action #{class_name.camelize}.\n" \ - "Should be in app/logux/#{class_namespace.downcase}/#{class_path}.rb" - raise_error_for_failed_find(message) - end - - def find_policy_class - "Policies::#{class_namespace}::#{class_name}".constantize - rescue NameError - message = - "Unable to find action policy #{class_name.camelize}.\n" \ - "Should be in app/logux/#{class_namespace.downcase}/#{class_path}.rb" - raise_error_for_failed_find(message) - end - - def class_name - if subscribe? - action.channel_name.camelize - else - action.type.split('/')[0..-2].map(&:camelize).join('::') - end - end - - private - - def class_namespace - subscribe? ? 'Channels' : 'Actions' - end - - def subscribe? - action.type == 'logux/subscribe' - end - - def action? - !subscribe? - end - - def class_path - "#{class_namespace}::#{class_name}".underscore - end - - def raise_error_for_failed_find(message) - exception_class = action? ? UnknownActionError : UnknownChannelError - raise exception_class.new(message, meta: meta) - end - end -end diff --git a/lib/logux/client.rb b/lib/logux/client.rb deleted file mode 100644 index 21a05d8..0000000 --- a/lib/logux/client.rb +++ /dev/null @@ -1,21 +0,0 @@ -# frozen_string_literal: true - -module Logux - class Client - attr_reader :logux_host - - def initialize(logux_host: Logux.configuration.logux_host) - @logux_host = logux_host - end - - def post(params) - client.post(params.to_json, - content_type: :json, - accept: :json) - end - - def client - @client ||= RestClient::Resource.new(logux_host, verify_ssl: false) - end - end -end diff --git a/lib/logux/error_renderer.rb b/lib/logux/error_renderer.rb deleted file mode 100644 index 84692c0..0000000 --- a/lib/logux/error_renderer.rb +++ /dev/null @@ -1,40 +0,0 @@ -# frozen_string_literal: true - -module Logux - class ErrorRenderer - attr_reader :exception - - def initialize(exception) - @exception = exception - end - - def message - case exception - when Logux::WithMetaError - build_message(exception, exception.meta.id) - when Logux::UnauthorizedError - build_message(exception, exception.message) - when StandardError - # some runtime error that should be fixed - render_stardard_error(exception) - end - end - - private - - def render_stardard_error(exception) - if Logux.configuration.render_backtrace_on_error - ['error', exception.message + "\n" + exception.backtrace.join("\n")] - else - ['error', 'Please look server logs for more information'] - end - end - - def build_message(exception, additional_info) - [ - exception.class.name.demodulize.camelize(:lower).gsub(/Error/, ''), - additional_info - ] - end - end -end diff --git a/lib/logux/meta.rb b/lib/logux/meta.rb deleted file mode 100644 index b66264a..0000000 --- a/lib/logux/meta.rb +++ /dev/null @@ -1,36 +0,0 @@ -# frozen_string_literal: true - -module Logux - class Meta < Hash - def initialize(source_hash = {}) - merge!(source_hash.stringify_keys) - - self['id'] ||= Logux.generate_action_id - self['time'] ||= self['id'].split(' ').first - end - - def node_id - id.split(' ').second - end - - def user_id - node_id.split(':').first - end - - def client_id - node_id.split(':')[0..1].join(':') - end - - def logux_order - time + ' ' + id.split(' ')[1..-1].join(' ') - end - - def time - fetch('time') - end - - def id - fetch('id') - end - end -end diff --git a/lib/logux/model/updates_deprecator.rb b/lib/logux/model/updates_deprecator.rb index 5c53e42..464779f 100644 --- a/lib/logux/model/updates_deprecator.rb +++ b/lib/logux/model/updates_deprecator.rb @@ -5,17 +5,15 @@ module Model class UpdatesDeprecator EVENT = 'logux.insecure_update' - class << self - def watch(args = {}, &block) - new(args).watch(&block) - end + def self.call(options = {}, &block) + new(options).call(&block) end - def initialize(level: :warn) - @level = level + def initialize(options) + @options = options end - def watch(&block) + def call(&block) callback = lambda(&method(:handle_insecure_update)) ActiveSupport::Notifications.subscribed(callback, EVENT, &block) end @@ -42,13 +40,19 @@ def notify_about_insecure_update(insecure_attributes) Logux tracked #{pluralized_attributes} (#{insecure_attributes.join(', ')}) should be updated using model.logux.update(...) TEXT - case @level + case level when :warn ActiveSupport::Deprecation.warn(message) when :error raise InsecureUpdateError, message end end + + DEFAULT_LEVEL = :warn + + def level + @options[:level] || DEFAULT_LEVEL + end end end end diff --git a/lib/logux/node.rb b/lib/logux/node.rb deleted file mode 100644 index 3a3c972..0000000 --- a/lib/logux/node.rb +++ /dev/null @@ -1,37 +0,0 @@ -# frozen_string_literal: true - -module Logux - class Node - include Singleton - - attr_accessor :last_time, :sequence - attr_writer :node_id - - def generate_action_id - mutex.synchronize do - if last_time && now_time <= last_time - @sequence += 1 - else - @sequence = 0 - @last_time = now_time - end - - "#{last_time} #{node_id} #{sequence}" - end - end - - def node_id - @node_id ||= "server:#{Nanoid.generate(size: 8)}" - end - - private - - def now_time - Time.now.to_datetime.strftime('%Q') - end - - def mutex - @mutex ||= Mutex.new - end - end -end diff --git a/lib/logux/policy.rb b/lib/logux/policy.rb deleted file mode 100644 index d3fef60..0000000 --- a/lib/logux/policy.rb +++ /dev/null @@ -1,14 +0,0 @@ -# frozen_string_literal: true - -module Logux - class Policy - class UnauthorizedError < StandardError; end - - attr_reader :action, :meta - - def initialize(action:, meta:) - @action = action - @meta = meta - end - end -end diff --git a/lib/logux/policy_caller.rb b/lib/logux/policy_caller.rb deleted file mode 100644 index 0d1a7c5..0000000 --- a/lib/logux/policy_caller.rb +++ /dev/null @@ -1,34 +0,0 @@ -# frozen_string_literal: true - -module Logux - class PolicyCaller - attr_reader :action, :meta - - delegate :logger, :configuration, to: :Logux - - def initialize(action:, meta:) - @action = action - @meta = meta - end - - def call! - logger.debug('Searching policy for Logux action:' \ - " #{action}, meta: #{meta}") - policy.public_send("#{action.action_type}?") - rescue Logux::UnknownActionError, Logux::UnknownChannelError => e - raise e if configuration.verify_authorized - - logger.warn(e) - end - - private - - def class_finder - @class_finder ||= Logux::ClassFinder.new(action: action, meta: meta) - end - - def policy - class_finder.find_policy_class.new(action: action, meta: meta) - end - end -end diff --git a/lib/logux/process.rb b/lib/logux/process.rb deleted file mode 100644 index d198d87..0000000 --- a/lib/logux/process.rb +++ /dev/null @@ -1,9 +0,0 @@ -# frozen_string_literal: true - -module Logux - module Process - autoload :Batch, 'logux/process/batch' - autoload :Auth, 'logux/process/auth' - autoload :Action, 'logux/process/action' - end -end diff --git a/lib/logux/process/action.rb b/lib/logux/process/action.rb deleted file mode 100644 index 127606c..0000000 --- a/lib/logux/process/action.rb +++ /dev/null @@ -1,60 +0,0 @@ -# frozen_string_literal: true - -module Logux - module Process - class Action - attr_reader :stream, :chunk - attr_accessor :stop_process - - def initialize(stream:, chunk:) - @stream = stream - @chunk = chunk - end - - def call - process_authorization! - process_action! - end - - def action_from_chunk - @action_from_chunk ||= chunk[:action] - end - - def meta_from_chunk - @meta_from_chunk ||= chunk[:meta] - end - - def stop_process? - @stop_process ||= false - end - - def stop_process! - @stop_process = true - end - - private - - def process_action! - return if stop_process? - - action_caller = Logux::ActionCaller.new( - action: action_from_chunk, - meta: meta_from_chunk - ) - - stream.write(action_caller.call!.format) - end - - def process_authorization! - policy_caller = Logux::PolicyCaller.new(action: action_from_chunk, - meta: meta_from_chunk) - policy_check = policy_caller.call! - status = policy_check ? :approved : :forbidden - stream.write([status, meta_from_chunk.id]) - return stream.write(',') if policy_check - - stop_process! - end - end - end -end diff --git a/lib/logux/process/auth.rb b/lib/logux/process/auth.rb deleted file mode 100755 index b10f8bb..0000000 --- a/lib/logux/process/auth.rb +++ /dev/null @@ -1,27 +0,0 @@ -# frozen_string_literal: true - -module Logux - module Process - class Auth - attr_reader :stream, :chunk - - def initialize(stream:, chunk:) - @stream = stream - @chunk = chunk - end - - def call - authed = Logux.configuration.auth_rule.call(user_id, chunk.credentials) - return stream.write(['authenticated', chunk.auth_id]) if authed - - stream.write(['denied', chunk.auth_id]) - end - - private - - def user_id - chunk.node_id.split(':').first - end - end - end -end diff --git a/lib/logux/process/batch.rb b/lib/logux/process/batch.rb deleted file mode 100644 index e8181a5..0000000 --- a/lib/logux/process/batch.rb +++ /dev/null @@ -1,59 +0,0 @@ -# frozen_string_literal: true - -module Logux - module Process - class Batch - attr_reader :stream, :batch - - def initialize(stream:, batch:) - @stream = stream - @batch = batch - end - - def call - last_chunk = batch.size - 1 - preprocessed_batch.map.with_index do |chunk, index| - case chunk[:type] - when :action - process_action(chunk: chunk.slice(:action, :meta)) - when :auth - process_auth(chunk: chunk[:auth]) - end - stream.write(',') if index != last_chunk - end - end - - def process_action(chunk:) - Logux::Process::Action.new(stream: stream, chunk: chunk).call - end - - def process_auth(chunk:) - Logux::Process::Auth.new(stream: stream, chunk: chunk).call - end - - def preprocessed_batch - @preprocessed_batch ||= batch.map do |chunk| - case chunk[0] - when 'action' - preprocess_action(chunk) - when 'auth' - preprocess_auth(chunk) - end - end - end - - def preprocess_action(chunk) - { type: :action, - action: Logux::Actions.new(chunk[1]), - meta: Logux::Meta.new(chunk[2]) } - end - - def preprocess_auth(chunk) - { type: :auth, - auth: Logux::Auth.new(node_id: chunk[1], - credentials: chunk[2], - auth_id: chunk[3]) } - end - end - end -end diff --git a/lib/logux/response.rb b/lib/logux/response.rb deleted file mode 100644 index 2eea679..0000000 --- a/lib/logux/response.rb +++ /dev/null @@ -1,18 +0,0 @@ -# frozen_string_literal: true - -module Logux - class Response - attr_reader :status, :action, :meta, :custom_data - - def initialize(status, action:, meta:, custom_data: nil) - @status = status - @action = action - @meta = meta - @custom_data = custom_data - end - - def format - [status, custom_data || meta.id] - end - end -end diff --git a/lib/logux/stream.rb b/lib/logux/stream.rb deleted file mode 100644 index 5f9424c..0000000 --- a/lib/logux/stream.rb +++ /dev/null @@ -1,25 +0,0 @@ -# frozen_string_literal: true - -module Logux - class Stream - attr_reader :stream - - delegate :close, to: :stream - - def initialize(stream) - @stream = stream - end - - def write(payload) - processed_payload = process(payload) - Logux.logger.debug("Write to Logux response: #{processed_payload}") - stream.write(processed_payload) - end - - private - - def process(payload) - payload.is_a?(::String) ? payload : payload.to_json - end - end -end diff --git a/lib/logux/test.rb b/lib/logux/test.rb deleted file mode 100644 index 3dec4e5..0000000 --- a/lib/logux/test.rb +++ /dev/null @@ -1,35 +0,0 @@ -# frozen_string_literal: true - -module Logux - module Test - class << self - attr_accessor :http_requests_enabled - - def enable_http_requests! - raise ArgumentError unless block_given? - - begin - self.http_requests_enabled = true - yield - ensure - self.http_requests_enabled = false - end - end - end - - module Client - def post(params) - if Logux::Test.http_requests_enabled - super(params) - else - Logux::Test::Store.instance.add(params.to_json) - end - end - end - - autoload :Helpers, 'logux/test/helpers' - autoload :Store, 'logux/test/store' - autoload :Matchers, 'logux/test/matchers' - end -end -Logux::Client.prepend Logux::Test::Client diff --git a/lib/logux/test/helpers.rb b/lib/logux/test/helpers.rb deleted file mode 100644 index cfb2cbe..0000000 --- a/lib/logux/test/helpers.rb +++ /dev/null @@ -1,75 +0,0 @@ -# frozen_string_literal: true - -module Logux - module Test - module Helpers - extend ActiveSupport::Concern - - included do - before do - Logux::Test::Store.instance.reset! - end - end - - def logux_store - Logux::Test::Store.instance.data - end - - def send_to_logux(*commands) - Logux::Test::Matchers::SendToLogux.new(*commands) - end - - def a_logux_meta_with(attributes = {}) - RSpec::Matchers::BuiltIn::Include.new(attributes.stringify_keys) - end - alias a_logux_meta a_logux_meta_with - - def a_logux_action_with(attributes = {}) - RSpec::Matchers::BuiltIn::Include.new(attributes.stringify_keys) - end - alias a_logux_action a_logux_action_with - - def logux_approved(meta = nil) - Logux::Test::Matchers::ResponseChunks.new( - meta: meta, includes: ['approved'], excludes: %w[forbidden error] - ) - end - - def logux_processed(meta = nil) - Logux::Test::Matchers::ResponseChunks.new( - meta: meta, includes: ['processed'], excludes: %w[forbidden error] - ) - end - - def logux_forbidden(meta = nil) - Logux::Test::Matchers::ResponseChunks.new( - meta: meta, includes: ['forbidden'] - ) - end - - def logux_errored(meta = nil) - Logux::Test::Matchers::ResponseChunks.new( - meta: meta, includes: ['error'] - ) - end - - def logux_authenticated(meta = nil) - Logux::Test::Matchers::ResponseChunks.new( - meta: meta, includes: ['authenticated'] - ) - end - - def logux_unauthorized(meta = nil) - Logux::Test::Matchers::ResponseChunks.new( - meta: meta, includes: ['unauthorized'] - ) - end - - def logux_denied(meta = nil) - Logux::Test::Matchers::ResponseChunks.new( - meta: meta, includes: ['denied'] - ) - end - end - end -end diff --git a/lib/logux/test/matchers.rb b/lib/logux/test/matchers.rb deleted file mode 100644 index c5cbb5f..0000000 --- a/lib/logux/test/matchers.rb +++ /dev/null @@ -1,10 +0,0 @@ -# frozen_string_literal: true - -module Logux - module Test - module Matchers - autoload :SendToLogux, 'logux/test/matchers/send_to_logux' - autoload :ResponseChunks, 'logux/test/matchers/response_chunks' - end - end -end diff --git a/lib/logux/test/matchers/base.rb b/lib/logux/test/matchers/base.rb deleted file mode 100644 index f6ab8e8..0000000 --- a/lib/logux/test/matchers/base.rb +++ /dev/null @@ -1,25 +0,0 @@ -# frozen_string_literal: true - -module Logux - module Test - module Matchers - class Base - attr_reader :expected - - def initialize(*expected) - @expected = expected - end - - def supports_block_expectations? - true - end - - private - - def pretty(obj) - JSON.pretty_generate(obj) - end - end - end - end -end diff --git a/lib/logux/test/matchers/response_chunks.rb b/lib/logux/test/matchers/response_chunks.rb deleted file mode 100644 index 4db150e..0000000 --- a/lib/logux/test/matchers/response_chunks.rb +++ /dev/null @@ -1,48 +0,0 @@ -# frozen_string_literal: true - -require_relative 'base' - -module Logux - module Test - module Matchers - class ResponseChunks < Base - attr_reader :includes, :excludes, :meta - - def initialize(meta:, includes:, excludes: []) - @meta = meta - @includes = includes - @excludes = excludes - end - - def matches?(actual) - @actual = JSON.parse(actual.body) - - match_includes? && match_excludes? - end - - def failure_message - data = "expected that #{pretty(@actual)} to has " \ - "#{includes.join(', ')} chunks" - !excludes.empty? && data += " and doesn't" \ - " has #{excludes.join(', ')} chunks" - data - end - - private - - def match_includes? - @actual.any? do |command| - command.first.in?(includes) && - (meta.nil? || (meta.present? && command[1] == meta)) - end - end - - def match_excludes? - @actual.empty? || @actual.none? do |command| - command.first.in?(excludes) - end - end - end - end - end -end diff --git a/lib/logux/test/matchers/send_to_logux.rb b/lib/logux/test/matchers/send_to_logux.rb deleted file mode 100644 index f0692b0..0000000 --- a/lib/logux/test/matchers/send_to_logux.rb +++ /dev/null @@ -1,51 +0,0 @@ -# frozen_string_literal: true - -require_relative 'base' - -module Logux - module Test - module Matchers - class SendToLogux < Base - def matches?(actual) - @difference = state_changes_inside { actual.call } - return !@difference.empty? if expected.empty? - - expected.all? do |ex| - @difference.find do |state| - state['commands'].any? do |c| - match_commands?(c, ex) - end - end - end - end - - def failure_message - "expected that #{pretty(@difference)} to include "\ - "commands #{pretty(expected)}" - end - - private - - def state_changes_inside - before_state = Logux::Test::Store.instance.data.dup - yield - after_state = Logux::Test::Store.instance.data - - (after_state - before_state).map { |d| JSON.parse(d) } - end - - def match_commands?(stored_command, expected_command) - expected_command.each_with_index.all? do |part, index| - part.stringify_keys! if part.is_a?(Hash) - matcher = if part.is_a?(RSpec::Matchers::BuiltIn::BaseMatcher) - part - else - RSpec::Matchers::BuiltIn::Eq.new(part) - end - matcher.matches?(stored_command[index]) - end - end - end - end - end -end diff --git a/lib/logux/test/store.rb b/lib/logux/test/store.rb deleted file mode 100644 index a96dcdf..0000000 --- a/lib/logux/test/store.rb +++ /dev/null @@ -1,21 +0,0 @@ -# frozen_string_literal: true - -module Logux - module Test - class Store - include Singleton - - def add(params) - data << params - end - - def data - @data ||= [] - end - - def reset! - @data = [] - end - end - end -end diff --git a/lib/logux/version.rb b/lib/logux/version.rb index 321c628..43e943c 100644 --- a/lib/logux/version.rb +++ b/lib/logux/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Logux - VERSION = '0.1.1' + VERSION = '0.2.0' end diff --git a/lib/logux_rails.rb b/lib/logux_rails.rb index 24b0769..f317e6e 100644 --- a/lib/logux_rails.rb +++ b/lib/logux_rails.rb @@ -1,3 +1,24 @@ # frozen_string_literal: true -require 'logux' +require 'action_controller' +require 'active_support' +require 'logux/rack' +require 'rails/engine' +require 'logux/engine' + +module Logux + autoload :Model, 'logux/model' + + configurable %i[ + action_watcher + action_watcher_options + ] + + configuration_defaults do |config| + config.action_watcher = Logux::Model::UpdatesDeprecator + config.action_watcher_options = { level: :error } + config.logger = Rails.logger if defined?(Rails.logger) + config.logger ||= ActiveSupport::Logger.new(STDOUT) + config.on_error = proc {} + end +end diff --git a/lib/tasks/logux_tasks.rake b/lib/tasks/logux_tasks.rake index 94d0792..cb70ea4 100644 --- a/lib/tasks/logux_tasks.rake +++ b/lib/tasks/logux_tasks.rake @@ -1,46 +1,19 @@ # frozen_string_literal: true -# rubocop:disable Metrics/BlockLength -namespace :logux do - desc 'Lists all Logux action types' - task actions: :environment do - Dir[Rails.root.join('app', 'logux', 'actions', '**', '*.rb')].each do |file| - require file - end +require 'logux/rake_tasks' - output = [%w[action.type Class#method]] - Logux::ActionController.descendants.sort_by(&:name).each do |klass| - klass.instance_methods(false).sort.each do |action| - output << [ - "#{klass.name.gsub(/^Actions::/, '').underscore}/#{action}", - "#{klass.name}##{action}" - ] - end - end +module Logux + class RakeTasks + protected - first_column_length = output.map(&:first).max_by(&:length).length - output.each do |action, klass_name| - puts "#{action.rjust(first_column_length, ' ')} #{klass_name}" + def default_actions_path + ::Rails.root.join('app', 'logux', 'actions') end - end - - desc 'Lists all Logux channels' - task channels: :environment do - path = Rails.root.join('app', 'logux', 'channels', '**', '*.rb') - Dir[path].each { |file| require file } - output = [%w[channel Class]] - Logux::ChannelController.descendants.map(&:name).sort.each do |klass_name| - output << [ - klass_name.gsub(/^Channels::/, '').underscore, - klass_name - ] - end - - first_column_length = output.map(&:first).max_by(&:length).length - output.each do |channel, klass_name| - puts "#{channel.rjust(first_column_length, ' ')} #{klass_name}" + def default_channels_path + ::Rails.root.join('app', 'logux', 'channels') end end end -# rubocop:enable Metrics/BlockLength + +Logux::RakeTasks.new diff --git a/logux_rails.gemspec b/logux_rails.gemspec index 10a808a..dd254d5 100644 --- a/logux_rails.gemspec +++ b/logux_rails.gemspec @@ -22,11 +22,8 @@ Gem::Specification.new do |spec| spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } spec.require_paths = ['lib'] - spec.add_dependency 'colorize' - spec.add_dependency 'configurations' - spec.add_dependency 'nanoid' + spec.add_dependency 'logux-rack', '>= 0.1.0' spec.add_dependency 'rails', '>= 5.0', '< 6.1' - spec.add_dependency 'rest-client' spec.add_development_dependency 'appraisal', '~> 2.2' spec.add_development_dependency 'bundler', '~> 1.16' spec.add_development_dependency 'combustion', '~> 1.1.0' diff --git a/spec/logux/action_caller_spec.rb b/spec/logux/action_caller_spec.rb index d3d99d2..ac38504 100644 --- a/spec/logux/action_caller_spec.rb +++ b/spec/logux/action_caller_spec.rb @@ -1,38 +1,12 @@ # frozen_string_literal: true -require 'spec_helper' +require 'rails_helper' describe Logux::ActionCaller do let(:action_caller) { described_class.new(action: action, meta: meta) } let(:action) { create(:logux_actions_add) } let(:meta) { create(:logux_meta) } - describe '#call!' do - context 'when action defined' do - subject(:result) { action_caller.call! } - - before do - module Actions - class User < Logux::ActionController - def add - respond(:ok) - end - end - end - end - - after do - Actions::User.send :undef_method, :add - Actions.send :remove_const, :User - Actions.send :const_set, :User, Class.new - end - - it 'return ok' do - expect(result.status).to eq(:ok) - end - end - end - context 'when attributes updated' do context 'when insecure #update is called' do let(:action) { create(:logux_actions_post, type: 'post/rename') } diff --git a/spec/logux/action_controller_spec.rb b/spec/logux/action_controller_spec.rb deleted file mode 100644 index ab33e98..0000000 --- a/spec/logux/action_controller_spec.rb +++ /dev/null @@ -1,54 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -describe Logux::ActionController do - let(:action_controller) { described_class.new(action: action, meta: meta) } - let(:action) { create(:logux_actions_subscribe) } - let(:user) { User.find_or_create_by(id: 1, name: 'test') } - let(:meta) { Logux::Meta.new } - - describe '#respond' do - subject(:response) { action_controller.respond(:processed) } - - it 'returns logux response' do - expect(response).to have_attributes( - status: :processed, action: action, custom_data: nil - ) - end - - it 'sets the meta with time' do - expect(response.meta).to have_key('time') - end - end - - describe '.verify_authorized!' do - subject(:verify_authorized!) { described_class.verify_authorized! } - - around do |example| - Logux.configuration.verify_authorized = false - example.call - Logux.configuration.verify_authorized = true - end - - it 'sets to true' do - expect { verify_authorized! } - .to change { Logux.configuration.verify_authorized } - .from(false) - .to(true) - end - end - - describe '.unverify_authorized!' do - subject(:unverify_authorized!) { described_class.unverify_authorized! } - - before { Logux.configuration.verify_authorized = true } - - it 'sets to false' do - expect { unverify_authorized! } - .to change { Logux.configuration.verify_authorized } - .from(true) - .to(false) - end - end -end diff --git a/spec/logux/actions_spec.rb b/spec/logux/actions_spec.rb deleted file mode 100644 index f7d4ec5..0000000 --- a/spec/logux/actions_spec.rb +++ /dev/null @@ -1,45 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -describe Logux::Actions do - let(:actions) do - described_class.new( - type: 'user/add', channel: 'project/123', data: 'data' - ) - end - - describe '#action_type' do - subject { actions.action_type } - - it { is_expected.to eq 'add' } - end - - describe '#action_name' do - subject { actions.action_name } - - it { is_expected.to eq 'user' } - end - - describe '#channel_name' do - subject { actions.channel_name } - - it { is_expected.to eq 'project' } - end - - describe '#channel_id' do - subject { actions.channel_id } - - it { is_expected.to eq '123' } - end - - describe 'permitted attributes' do - it 'has actions params unpermitted' do - expect(actions).not_to be_permitted - end - - it 'permits params' do - expect(actions.permit(:data)).to be_permitted - end - end -end diff --git a/spec/logux/add_spec.rb b/spec/logux/add_spec.rb deleted file mode 100644 index a633efb..0000000 --- a/spec/logux/add_spec.rb +++ /dev/null @@ -1,21 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -describe Logux::Add, timecop: true do - let(:request) { described_class.new } - - describe '#call' do - let(:action) { { id: 1 } } - let(:meta) { create(:logux_meta) } - let(:logux_commands) do - [['action', { id: 1 }, meta], ['action', { id: 2 }, meta]] - end - - it 'return processed' do - expect { request.call([[action, meta]]) }.to send_to_logux( - ['action', { id: 1 }, a_logux_meta] - ) - end - end -end diff --git a/spec/logux/channel_controller_spec.rb b/spec/logux/channel_controller_spec.rb deleted file mode 100644 index 6715953..0000000 --- a/spec/logux/channel_controller_spec.rb +++ /dev/null @@ -1,48 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -describe Logux::ChannelController do - let(:controller_class) do - FakeController = Class.new(described_class) do - def initial_data - [{ type: 'action' }] - end - end - end - let(:channel_controller) { controller_class.new(action: action, meta: meta) } - let(:user) { User.find_or_create_by(id: 1, name: 'test') } - let(:meta) { Logux::Meta.new } - - describe '#subscribe' do - subject(:subscribe) { channel_controller.subscribe } - - let(:action) { create(:logux_actions_subscribe) } - - context 'when ActiveRecord defined' do - it 'tries to find record by chanel data' do - expect { subscribe }.to send_to_logux(['action', { type: 'action' }]) - end - end - end - - describe '#since_time' do - subject(:since_time) { channel_controller.since_time } - - context 'when action.since defined' do - let(:action) { create(:logux_actions_subscribe_since) } - - it 'tries to find record by chanel data' do - expect(since_time).to eql(Time.at(100).to_datetime) - end - end - - context 'when action.since not defined' do - let(:action) { create(:logux_actions_subscribe) } - - it 'tries to find record by chanel data' do - expect(since_time).to be_nil - end - end - end -end diff --git a/spec/logux/class_finder_spec.rb b/spec/logux/class_finder_spec.rb deleted file mode 100644 index 34655e8..0000000 --- a/spec/logux/class_finder_spec.rb +++ /dev/null @@ -1,60 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -describe Logux::ClassFinder do - let(:finder) { described_class.new(action: action, meta: meta) } - let(:meta) { create(:logux_meta) } - - describe '#class_name' do - subject(:class_name) { finder.class_name } - - let(:action) do - create(:logux_actions_add, type: 'test/test/name/try/user/add') - end - - it 'returns nested classes' do - expect(class_name).to eq('Test::Test::Name::Try::User') - end - end - - describe '#find_policy_class' do - subject(:policy_class) { finder.find_policy_class } - - context 'with unknown action' do - let(:action) { create(:logux_actions_unknown) } - - it 'raise an error for unknown action error' do - expect { policy_class }.to raise_error(Logux::UnknownActionError) - end - end - - context 'with unknown subscribe' do - let(:action) { create(:logux_actions_unknown_subscribe) } - - it 'raise an error for unknown action error' do - expect { policy_class }.to raise_error(Logux::UnknownChannelError) - end - end - end - - describe '#find_action_class' do - subject(:action_class) { finder.find_action_class } - - context 'with unknown action' do - let(:action) { create(:logux_actions_unknown) } - - it 'raise an error for unknown action error' do - expect { action_class }.to raise_error(Logux::UnknownActionError) - end - end - - context 'with unknown subscribe' do - let(:action) { create(:logux_actions_unknown_subscribe) } - - it 'raise an error for unknown action error' do - expect { action_class }.to raise_error(Logux::UnknownChannelError) - end - end - end -end diff --git a/spec/logux/client_spec.rb b/spec/logux/client_spec.rb deleted file mode 100644 index d738089..0000000 --- a/spec/logux/client_spec.rb +++ /dev/null @@ -1,27 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -describe Logux::Client do - let(:client) { described_class.new } - let(:meta) { create(:logux_meta) } - let(:commands) do - [['action', { id: 1 }, meta], ['action', { id: 2 }, meta]] - end - let(:params) do - { - version: Logux::PROTOCOL_VERSION, - password: nil, - commands: commands - } - end - - describe '#post' do - it 'performs request' do - expect { client.post(params) }.to send_to_logux( - ['action', { id: 1 }, a_logux_meta], - ['action', { id: 2 }, a_logux_meta] - ) - end - end -end diff --git a/spec/logux/error_renderer_spec.rb b/spec/logux/error_renderer_spec.rb deleted file mode 100644 index f9a4e7d..0000000 --- a/spec/logux/error_renderer_spec.rb +++ /dev/null @@ -1,59 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -describe Logux::ErrorRenderer do - let(:action_id) { '123 10:uuid 0' } - let(:meta) { create(:logux_meta, id: action_id) } - - describe '#message' do - def build_message(exception) - described_class.new(exception).message - end - - it 'returns correct error message for UnknownActionError' do - exception = Logux::UnknownActionError.new('test', meta: meta) - - expect(build_message(exception)).to eq(['unknownAction', action_id]) - end - - it 'returns correct error message for UnknownChannelError' do - exception = Logux::UnknownChannelError.new('test', meta: meta) - - expect(build_message(exception)).to eq(['unknownChannel', action_id]) - end - - it 'returns correct error message for UnauthorizedError' do - exception = Logux::UnauthorizedError.new('test') - - expect(build_message(exception)).to eq(%w[unauthorized test]) - end - - context 'when Logux.configuration.render_backtrace_on_error is true' do - around do |example| - Logux.configuration.render_backtrace_on_error = true - example.run - Logux.configuration.render_backtrace_on_error = false - end - - it 'returns correct error with backtrace for some unknown error' do - exception = StandardError.new('Test') - exception.set_backtrace(caller) - - expect(build_message(exception)).to eq( - ['error', "Test\n" + exception.backtrace.join("\n")] - ) - end - end - - context 'when Logux.configuration.render_backtrace_on_error is false' do - it 'returns correct error message for some unknown error' do - exception = StandardError.new - - expect(build_message(exception)).to eq( - ['error', 'Please look server logs for more information'] - ) - end - end - end -end diff --git a/spec/logux/meta_spec.rb b/spec/logux/meta_spec.rb deleted file mode 100644 index 8f0e2c2..0000000 --- a/spec/logux/meta_spec.rb +++ /dev/null @@ -1,87 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -describe Logux::Meta do - subject(:meta) { described_class.new(attributes) } - - let(:attributes) { {} } - - describe '#new' do - context 'with empty meta' do - it 'generates id' do - expect(meta.id).not_to be nil - end - - it 'generates time' do - expect(meta.time).not_to be nil - end - end - - context 'with id' do - let(:attributes) { { id: '112 10:uuid 0' } } - - it 'fills time' do - expect(meta.time).to eq('112') - end - end - - context 'with meta' do - let(:time) { '4321' } - let(:id) { '1234' } - let(:attributes) { { id: id, time: time } } - - it 'does not rewrite id if it is provided' do - expect(meta.id).to eq(id) - end - - it 'does not rewrite time if it is provided' do - expect(meta.time).to eq(time) - end - end - end - - describe '#logux_order' do - let(:attributes) { { id: '100 10:uuid 0', time: '200' } } - - it 'combines id and time' do - expect(meta.logux_order).to eq('200 10:uuid 0') - end - end - - describe '#user_id' do - let(:attributes) { { id: '1 user:client:id 0' } } - - it 'parses user ID' do - expect(meta.user_id).to eq('user') - end - end - - describe '#node_id' do - let(:attributes) { { id: '1 user:client:id 0' } } - - it 'parses node ID' do - expect(meta.node_id).to eq('user:client:id') - end - end - - describe '#client_id' do - let(:attributes) { { id: id } } - - context 'with full node ID' do - let(:id) { '1 user:client:id 0' } - - it 'parses client ID' do - expect(meta.client_id).to eq('user:client') - end - end - - context 'with short node ID' do - let(:id) { '1 id 0' } - - it 'parses client ID' do - expect(meta.client_id).to eq('id') - end - end - end -end diff --git a/spec/logux/model/updates_deprecator_spec.rb b/spec/logux/model/updates_deprecator_spec.rb index c01a680..6e7ba77 100644 --- a/spec/logux/model/updates_deprecator_spec.rb +++ b/spec/logux/model/updates_deprecator_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'spec_helper' +require 'rails_helper' describe Logux::Model::UpdatesDeprecator do let(:post) { create(:post) } @@ -8,7 +8,7 @@ context 'with error level' do it 'raises error when insecure update is detected' do expect do - described_class.watch(level: :error) do + described_class.call(level: :error) do post.update(title: 'new title') end end.to raise_error(Logux::Model::InsecureUpdateError) @@ -16,7 +16,7 @@ it 'does not raise error when update is secure' do expect do - described_class.watch(level: :error) do + described_class.call(level: :error) do post.update(updated_at: Time.now) end end.not_to raise_error @@ -26,7 +26,7 @@ context 'with warn level' do it 'outputs deprecation warning when update is detected' do expect do - described_class.watch(level: :warn) do + described_class.call(level: :warn) do post.update(title: 'new title') end end.to output(/DEPRECATION WARNING/).to_stderr @@ -34,7 +34,7 @@ it 'uses warn level by default' do expect do - described_class.watch do + described_class.call do post.update(title: 'new title') end end.to output(/DEPRECATION WARNING/).to_stderr diff --git a/spec/logux/node_spec.rb b/spec/logux/node_spec.rb deleted file mode 100644 index 8416c2d..0000000 --- a/spec/logux/node_spec.rb +++ /dev/null @@ -1,39 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -describe Logux::Node do - let(:node) { described_class.instance } - - describe '#generate_action_id' do - subject(:action_id) { node.generate_action_id } - - it 'returns correct id' do - expect(action_id).to match(/^[0-9]{13} server:.{8} 0$/) - end - - context 'with action at the same time', timecop: true do - before do - node.sequence = 0 - node.last_time = nil - node.generate_action_id - end - - it 'returns 1 in sequence' do - expect(action_id).to match(/^[0-9]{13} server:.{8} 1$/) - end - end - end - - describe '#node_id' do - subject(:node_id) { node.node_id } - - it 'generates nanoid' do - expect(node_id).not_to be_empty - end - - it "doesn't change from call to call" do - expect(node_id).to eq(node.node_id) - end - end -end diff --git a/spec/logux/policy_caller_spec.rb b/spec/logux/policy_caller_spec.rb deleted file mode 100644 index 75e63d3..0000000 --- a/spec/logux/policy_caller_spec.rb +++ /dev/null @@ -1,49 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -describe Logux::PolicyCaller do - subject(:call!) { policy_caller.call! } - - let(:policy_caller) { described_class.new(action: action, meta: meta) } - let(:meta) { {} } - - context 'when request is not verified' do - let(:action) { create(:logux_actions_unknown) } - - before do - Logux.configuration.verify_authorized = false - allow(Logux.logger).to receive(:warn) - call! - Logux.configuration.verify_authorized = true - end - - it 'doesn\'t raise an error' do - expect(Logux.logger).to have_received(:warn).once - end - end - - context 'when verify_authorized' do - around do |example| - Logux.configuration.verify_authorized = true - example.call - Logux.configuration.verify_authorized = false - end - - context 'with unknown action' do - let(:action) { create(:logux_actions_unknown) } - - it 'raises an unknownActionError' do - expect { call! }.to raise_error(Logux::UnknownActionError) - end - end - - context 'with unknown subscribe' do - let(:action) { create(:logux_actions_unknown_subscribe) } - - it 'raises an unknownActionError' do - expect { call! }.to raise_error(Logux::UnknownChannelError) - end - end - end -end diff --git a/spec/logux/tasks/actions_spec.rb b/spec/logux/tasks/actions_spec.rb index ec80879..4999827 100644 --- a/spec/logux/tasks/actions_spec.rb +++ b/spec/logux/tasks/actions_spec.rb @@ -5,10 +5,6 @@ describe 'rake logux:actions', type: :task do subject(:task) { Rake::Task['logux:actions'] } - it 'preloads the Rails environment' do - expect(task.prerequisites).to include 'environment' - end - it 'outputs all action types and corresponding class and method names' do expect { task.execute }.to output( %r{blog/notes/add Actions::Blog::Notes#add} diff --git a/spec/logux/tasks/channels_spec.rb b/spec/logux/tasks/channels_spec.rb index ce77746..f7b53f1 100644 --- a/spec/logux/tasks/channels_spec.rb +++ b/spec/logux/tasks/channels_spec.rb @@ -5,10 +5,6 @@ describe 'rake logux:channels', type: :task do subject(:task) { Rake::Task['logux:channels'] } - it 'preloads the Rails environment' do - expect(task.prerequisites).to include 'environment' - end - it 'outputs all channels and corresponding class names' do expect { task.execute }.to output( /post Channels::Post/ diff --git a/spec/logux_spec.rb b/spec/logux_spec.rb deleted file mode 100644 index 64e3eb6..0000000 --- a/spec/logux_spec.rb +++ /dev/null @@ -1,109 +0,0 @@ -# frozen_string_literal: true - -describe Logux, timecop: true do - it 'has a version number' do - expect(Logux::VERSION).not_to be nil - end - - describe '.add' do - let(:action) { { type: 'action' } } - - describe 'http request' do - it 'makes request' do - stub = stub_request(:post, Logux.configuration.logux_host) - Logux::Test.enable_http_requests! { described_class.add(action) } - expect(stub).to have_been_requested - end - end - - it 'sends action with meta' do - expect { described_class.add(action) }.to send_to_logux( - ['action', a_logux_action_with(type: 'action'), a_logux_meta] - ) - end - end - - describe '.add_batch' do - let(:commands) do - [ - [{ 'type': 'action' }], - [{ 'type': 'action2' }] - ] - end - - describe 'http request' do - it 'makes a request' do - stub = stub_request(:post, Logux.configuration.logux_host) - Logux::Test.enable_http_requests! { described_class.add(commands) } - expect(stub).to have_been_requested - end - end - - it 'sends action with meta' do - expect { described_class.add_batch(commands) }.to send_to_logux( - ['action', a_logux_action_with(type: 'action'), a_logux_meta], - ['action', a_logux_action_with(type: 'action2'), a_logux_meta] - ) - end - end - - describe '.generate_action_id' do - subject(:action_id) { described_class.generate_action_id } - - it 'returns correct action id' do - expect(action_id).not_to be_empty - end - end - - describe '.undo' do - let(:meta) do - Logux::Meta.new( - id: '1 1:client:uuid 0', - users: ['3'], - reasons: ['user/1/lastValue'], - nodeIds: ['2:uuid'], - channels: ['user/1'] - ) - end - let(:reason) { 'error' } - - context 'when extra data is not provided' do - let(:request) { described_class.undo(meta, reason: reason) } - let(:logux_commands) do - [ - 'action', - { type: 'logux/undo', id: meta.id, reason: reason }, - a_logux_meta_with(clients: ['1:client']) - ] - end - - it 'makes request' do - expect { request }.to send_to_logux(logux_commands) - end - end - - context 'when data provided' do - let(:request) do - described_class.undo(meta, - reason: reason, - data: { errors: ['limitExceeded'] }) - end - let(:logux_commands) do - [ - 'action', - { - type: 'logux/undo', - id: meta.id, - reason: reason, - errors: ['limitExceeded'] - }, - a_logux_meta_with(clients: ['1:client']) - ] - end - - it 'makes request' do - expect { request }.to send_to_logux(logux_commands) - end - end - end -end