startback-websocket 0.14.0 → 0.14.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +3 -2
- data/README.md +64 -9
- data/lib/startback/ext/context.rb +6 -0
- data/lib/startback/ext.rb +1 -2
- data/lib/startback/websocket/app.rb +82 -0
- data/lib/startback/websocket/hub/app.rb +28 -0
- data/lib/startback/websocket/hub/builder.rb +55 -0
- data/lib/startback/websocket/hub/errors.rb +9 -0
- data/lib/startback/websocket/hub/message.rb +29 -0
- data/lib/startback/websocket/hub/middleware/command_handler.rb +34 -0
- data/lib/startback/websocket/hub/middleware/room_handler.rb +30 -0
- data/lib/startback/websocket/hub/middleware.rb +12 -0
- data/lib/startback/websocket/hub/participant.rb +16 -0
- data/lib/startback/websocket/hub/room.rb +46 -0
- data/lib/startback/websocket/hub.rb +15 -0
- data/lib/startback/websocket.rb +8 -0
- data/spec/spec_helper.rb +21 -32
- data/spec/unit/hub/test_builder.rb +141 -0
- data/spec/unit/hub/test_room.rb +27 -0
- data/spec/unit/test_app.rb +35 -0
- data/tasks/test.rake +0 -1
- metadata +20 -91
- data/lib/startback/audit/prometheus.rb +0 -87
- data/lib/startback/audit/shared.rb +0 -17
- data/lib/startback/audit/trailer.rb +0 -129
- data/lib/startback/audit.rb +0 -3
- data/lib/startback/caching/entity_cache.rb +0 -157
- data/lib/startback/caching/no_store.rb +0 -28
- data/lib/startback/caching/store.rb +0 -34
- data/lib/startback/context/h_factory.rb +0 -43
- data/lib/startback/context/middleware.rb +0 -53
- data/lib/startback/context.rb +0 -122
- data/lib/startback/errors.rb +0 -197
- data/lib/startback/event/agent.rb +0 -84
- data/lib/startback/event/bus/bunny/async.rb +0 -162
- data/lib/startback/event/bus/bunny.rb +0 -1
- data/lib/startback/event/bus/memory/async.rb +0 -45
- data/lib/startback/event/bus/memory/sync.rb +0 -35
- data/lib/startback/event/bus/memory.rb +0 -2
- data/lib/startback/event/bus.rb +0 -100
- data/lib/startback/event/engine.rb +0 -94
- data/lib/startback/event/ext/context.rb +0 -5
- data/lib/startback/event/ext/operation.rb +0 -13
- data/lib/startback/event.rb +0 -47
- data/lib/startback/ext/date_time.rb +0 -9
- data/lib/startback/ext/time.rb +0 -9
- data/lib/startback/model.rb +0 -6
- data/lib/startback/operation/error_operation.rb +0 -19
- data/lib/startback/operation/multi_operation.rb +0 -28
- data/lib/startback/operation.rb +0 -78
- data/lib/startback/services.rb +0 -11
- data/lib/startback/support/data_object.rb +0 -71
- data/lib/startback/support/env.rb +0 -41
- data/lib/startback/support/fake_logger.rb +0 -18
- data/lib/startback/support/hooks.rb +0 -48
- data/lib/startback/support/log_formatter.rb +0 -34
- data/lib/startback/support/logger.rb +0 -34
- data/lib/startback/support/operation_runner.rb +0 -150
- data/lib/startback/support/robustness.rb +0 -157
- data/lib/startback/support/transaction_manager.rb +0 -25
- data/lib/startback/support/transaction_policy.rb +0 -33
- data/lib/startback/support/world.rb +0 -54
- data/lib/startback/support.rb +0 -26
- data/lib/startback/version.rb +0 -8
- data/lib/startback/web/api.rb +0 -99
- data/lib/startback/web/auto_caching.rb +0 -85
- data/lib/startback/web/catch_all.rb +0 -52
- data/lib/startback/web/cors_headers.rb +0 -80
- data/lib/startback/web/health_check.rb +0 -49
- data/lib/startback/web/magic_assets/ng_html_transformer.rb +0 -80
- data/lib/startback/web/magic_assets/rake_tasks.rb +0 -64
- data/lib/startback/web/magic_assets.rb +0 -98
- data/lib/startback/web/middleware.rb +0 -13
- data/lib/startback/web/prometheus.rb +0 -16
- data/lib/startback/web/shield.rb +0 -58
- data/lib/startback.rb +0 -43
- data/spec/unit/audit/test_prometheus.rb +0 -72
- data/spec/unit/audit/test_trailer.rb +0 -105
- data/spec/unit/caching/test_entity_cache.rb +0 -136
- data/spec/unit/context/test_abstraction_factory.rb +0 -64
- data/spec/unit/context/test_dup.rb +0 -42
- data/spec/unit/context/test_fork.rb +0 -37
- data/spec/unit/context/test_h_factory.rb +0 -31
- data/spec/unit/context/test_middleware.rb +0 -45
- data/spec/unit/context/test_with_world.rb +0 -20
- data/spec/unit/context/test_world.rb +0 -17
- data/spec/unit/event/bus/memory/test_async.rb +0 -43
- data/spec/unit/event/bus/memory/test_sync.rb +0 -43
- data/spec/unit/support/hooks/test_after_hook.rb +0 -54
- data/spec/unit/support/hooks/test_before_hook.rb +0 -54
- data/spec/unit/support/operation_runner/test_around_run.rb +0 -156
- data/spec/unit/support/operation_runner/test_before_after_call.rb +0 -48
- data/spec/unit/support/test_data_object.rb +0 -156
- data/spec/unit/support/test_env.rb +0 -75
- data/spec/unit/support/test_robusteness.rb +0 -229
- data/spec/unit/support/test_transaction_manager.rb +0 -64
- data/spec/unit/support/test_world.rb +0 -72
- data/spec/unit/test_event.rb +0 -62
- data/spec/unit/test_operation.rb +0 -55
- data/spec/unit/test_support.rb +0 -40
- data/spec/unit/web/fixtures/assets/app/hello.es6 +0 -4
- data/spec/unit/web/fixtures/assets/app/hello.html +0 -1
- data/spec/unit/web/fixtures/assets/index.es6 +0 -1
- data/spec/unit/web/test_api.rb +0 -82
- data/spec/unit/web/test_auto_caching.rb +0 -81
- data/spec/unit/web/test_catch_all.rb +0 -77
- data/spec/unit/web/test_cors_headers.rb +0 -88
- data/spec/unit/web/test_healthcheck.rb +0 -59
- data/spec/unit/web/test_magic_assets.rb +0 -82
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
require 'sprockets'
|
|
2
|
-
module Startback
|
|
3
|
-
module Web
|
|
4
|
-
#
|
|
5
|
-
# Rack application & middleware that can be used to simplify javascript
|
|
6
|
-
# and css assets management, using Sprockets.
|
|
7
|
-
#
|
|
8
|
-
# Example:
|
|
9
|
-
#
|
|
10
|
-
# # Used as rack app, typically under a path
|
|
11
|
-
# Rack::Builder.new do
|
|
12
|
-
# map '/assets' do
|
|
13
|
-
# run Startback::Web::MagicAssets.new({
|
|
14
|
-
# folder: "/path/to/assets/src"
|
|
15
|
-
# })
|
|
16
|
-
# end
|
|
17
|
-
# run MyApp
|
|
18
|
-
# end
|
|
19
|
-
#
|
|
20
|
-
# # Used as a rack middleware, e.g. in a Sinatra application
|
|
21
|
-
# use Startback::Web::MagicAssets, {
|
|
22
|
-
# folder: "/path/to/assets/src",
|
|
23
|
-
# path: "/assets"
|
|
24
|
-
# }
|
|
25
|
-
#
|
|
26
|
-
# Sprocket configuration can be done through the `:sprocket` option:
|
|
27
|
-
#
|
|
28
|
-
# use Startback::Web::MagicAssets, {
|
|
29
|
-
# sprockets: {
|
|
30
|
-
# :css_compressor => :scss
|
|
31
|
-
# }
|
|
32
|
-
# }
|
|
33
|
-
#
|
|
34
|
-
class MagicAssets
|
|
35
|
-
|
|
36
|
-
DEFAULT_OPTIONS = {
|
|
37
|
-
sprockets: {},
|
|
38
|
-
plugins: {}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
def initialize(app, options = {})
|
|
42
|
-
app, options = nil, app if app.is_a?(Hash)
|
|
43
|
-
@app = app
|
|
44
|
-
@options = DEFAULT_OPTIONS.merge(options)
|
|
45
|
-
@sprockets = build_sprockets
|
|
46
|
-
end
|
|
47
|
-
attr_reader :sprockets
|
|
48
|
-
|
|
49
|
-
def call(env)
|
|
50
|
-
if new_env = is_match?(env)
|
|
51
|
-
@sprockets.call(new_env)
|
|
52
|
-
else
|
|
53
|
-
@app.call(env)
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def [](*args, &bl)
|
|
58
|
-
@sprockets.[](*args, &bl)
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
private
|
|
62
|
-
|
|
63
|
-
def path
|
|
64
|
-
@options[:path]
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def is_match?(env)
|
|
68
|
-
if @app.nil?
|
|
69
|
-
# Not used as a middleware, use this env and match
|
|
70
|
-
env
|
|
71
|
-
elsif env['PATH_INFO'].start_with?(path)
|
|
72
|
-
# Used as a middleware, and PATH_INFO starts with the
|
|
73
|
-
# assets path => strip it for sprockets
|
|
74
|
-
env.merge("PATH_INFO" => env["PATH_INFO"].sub(path, ""))
|
|
75
|
-
else
|
|
76
|
-
# No match, let @app execute with the untouched environment
|
|
77
|
-
nil
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
def build_sprockets
|
|
82
|
-
Sprockets::Environment.new.tap{|s|
|
|
83
|
-
Array(@options[:folder]).each do |folder|
|
|
84
|
-
s.append_path(folder)
|
|
85
|
-
end
|
|
86
|
-
@options[:sprockets].each_pair do |k,v|
|
|
87
|
-
s.public_send(:"#{k}=", v)
|
|
88
|
-
end
|
|
89
|
-
@options[:plugins].each do |p|
|
|
90
|
-
p.install(s)
|
|
91
|
-
end
|
|
92
|
-
}
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
end # class MagicAssets
|
|
96
|
-
end # module Web
|
|
97
|
-
end # module Startback
|
|
98
|
-
require_relative 'magic_assets/rake_tasks'
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
module Startback
|
|
2
|
-
module Web
|
|
3
|
-
module Middleware
|
|
4
|
-
|
|
5
|
-
protected
|
|
6
|
-
|
|
7
|
-
def context(env = @env)
|
|
8
|
-
::Startback::Context::Middleware.context(env) || Errors.server_error!("Unable to find context!!")
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
end # module Middleware
|
|
12
|
-
end # module Web
|
|
13
|
-
end # module Startback
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
require 'prometheus/middleware/exporter'
|
|
2
|
-
module Startback
|
|
3
|
-
module Web
|
|
4
|
-
#
|
|
5
|
-
# Can be used to expose the prometheus metrics inside a Startback
|
|
6
|
-
# application.
|
|
7
|
-
#
|
|
8
|
-
# Example:
|
|
9
|
-
#
|
|
10
|
-
# use Startback::Web::Prometheus
|
|
11
|
-
#
|
|
12
|
-
class Prometheus < Prometheus::Middleware::Exporter
|
|
13
|
-
|
|
14
|
-
end # class Prometheus
|
|
15
|
-
end # module Web
|
|
16
|
-
end # module Startback
|
data/lib/startback/web/shield.rb
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
module Startback
|
|
2
|
-
module Web
|
|
3
|
-
#
|
|
4
|
-
# This Rack middleware catches all known exceptions raised by sublayers
|
|
5
|
-
# in the Rack chain. Those exceptions are converted to proper HTTP error
|
|
6
|
-
# codes and friendly error messages encoded in json.
|
|
7
|
-
#
|
|
8
|
-
# Please check the Errors module about status codes used for each Startback
|
|
9
|
-
# error.
|
|
10
|
-
#
|
|
11
|
-
# This class aims at being used as top level of a Rack chain.
|
|
12
|
-
#
|
|
13
|
-
# Examples:
|
|
14
|
-
#
|
|
15
|
-
# Rack::Builder.new do
|
|
16
|
-
# use Startback::Web::Shield
|
|
17
|
-
# end
|
|
18
|
-
#
|
|
19
|
-
class Shield < Rack::Robustness
|
|
20
|
-
include Errors
|
|
21
|
-
|
|
22
|
-
self.no_catch_all
|
|
23
|
-
self.content_type 'application/json'
|
|
24
|
-
|
|
25
|
-
# Decoding errors from json and csv are considered user's fault
|
|
26
|
-
self.on(Finitio::TypeError){ 400 }
|
|
27
|
-
self.on(::NotImplementedError){ 501 }
|
|
28
|
-
|
|
29
|
-
# Various other codes for the framework specific error classes
|
|
30
|
-
self.on(Startback::Errors::Error) {|ex|
|
|
31
|
-
ex.class.status
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
# A bit of logic to choose the best error message for the user
|
|
35
|
-
# according to the error class
|
|
36
|
-
self.body{|ex|
|
|
37
|
-
body_for(ex).to_json
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
def body_for(ex)
|
|
41
|
-
ex = ex.root_cause if ex.is_a?(Finitio::TypeError)
|
|
42
|
-
body = { code: ex.class.name, description: ex.message }
|
|
43
|
-
return body unless ex.is_a?(Startback::Errors::Error)
|
|
44
|
-
return body unless ex.has_causes?
|
|
45
|
-
|
|
46
|
-
body[:causes] = ex.causes
|
|
47
|
-
.filter{|cause|
|
|
48
|
-
cause.is_a?(Startback::Errors::Error)
|
|
49
|
-
}
|
|
50
|
-
.map{|cause|
|
|
51
|
-
body_for(cause)
|
|
52
|
-
}
|
|
53
|
-
body
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
end # class Shield
|
|
57
|
-
end # module Web
|
|
58
|
-
end # module Startback
|
data/lib/startback.rb
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
require 'sinatra'
|
|
2
|
-
require 'rack/robustness'
|
|
3
|
-
require 'finitio'
|
|
4
|
-
require 'logger'
|
|
5
|
-
require 'path'
|
|
6
|
-
require 'ostruct'
|
|
7
|
-
require 'benchmark'
|
|
8
|
-
|
|
9
|
-
# Provides a reusable backend framework for backend components written
|
|
10
|
-
# in ruby.
|
|
11
|
-
#
|
|
12
|
-
# The framework installs conventions regarding:
|
|
13
|
-
#
|
|
14
|
-
# - The exposition of web service APIs (Framework::Api, on top of Sinatra)
|
|
15
|
-
# - Operations (Framework::Operation)
|
|
16
|
-
# - Error handling (Framework::Errors) and their handling in web APIs
|
|
17
|
-
# (based on Rack::Robustness)
|
|
18
|
-
# - General code support (Framework::Support modules & classes).
|
|
19
|
-
#
|
|
20
|
-
# Please refer to the documentation of those main abstractions for details.
|
|
21
|
-
#
|
|
22
|
-
module Startback
|
|
23
|
-
|
|
24
|
-
# Simply checks that a path exists of raise an error
|
|
25
|
-
def self._!(path)
|
|
26
|
-
Path(path).tap do |p|
|
|
27
|
-
raise "Missing #{p.basename}." unless p.exists?
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
require_relative 'startback/version'
|
|
32
|
-
require_relative 'startback/ext'
|
|
33
|
-
require_relative 'startback/errors'
|
|
34
|
-
require_relative 'startback/support'
|
|
35
|
-
require_relative 'startback/model'
|
|
36
|
-
require_relative 'startback/context'
|
|
37
|
-
require_relative 'startback/operation'
|
|
38
|
-
require_relative 'startback/services'
|
|
39
|
-
|
|
40
|
-
# Logger instance to use for the application
|
|
41
|
-
LOGGER = ::Startback::Support::Logger.new
|
|
42
|
-
|
|
43
|
-
end # module Startback
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'startback/audit'
|
|
3
|
-
module Startback
|
|
4
|
-
module Audit
|
|
5
|
-
describe Prometheus do
|
|
6
|
-
|
|
7
|
-
EXPORTER = Prometheus.new({
|
|
8
|
-
prefix: "hello",
|
|
9
|
-
labels: {
|
|
10
|
-
app_version: "1.0"
|
|
11
|
-
}
|
|
12
|
-
})
|
|
13
|
-
|
|
14
|
-
class Runner
|
|
15
|
-
include Startback::Support::OperationRunner
|
|
16
|
-
|
|
17
|
-
class IdealOp < Startback::Operation
|
|
18
|
-
def call
|
|
19
|
-
42
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
class ExceptionalOp < Startback::Operation
|
|
24
|
-
def call
|
|
25
|
-
raise "Oops"
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
around_run(EXPORTER)
|
|
30
|
-
def test
|
|
31
|
-
run IdealOp.new
|
|
32
|
-
end
|
|
33
|
-
def test_exp
|
|
34
|
-
run ExceptionalOp.new
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
describe 'The ideal case' do
|
|
39
|
-
before do
|
|
40
|
-
expect(EXPORTER.calls).to receive(:observe).with(
|
|
41
|
-
kind_of(Numeric),
|
|
42
|
-
hash_including(labels: {
|
|
43
|
-
operation: "Startback::Audit::Runner::IdealOp",
|
|
44
|
-
startback_version: Startback::VERSION,
|
|
45
|
-
app_version: "1.0"
|
|
46
|
-
}))
|
|
47
|
-
expect(EXPORTER.errors).not_to receive(:increment)
|
|
48
|
-
end
|
|
49
|
-
it 'runs the operation' do
|
|
50
|
-
expect(Runner.new.test).to eql(42)
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
describe 'The exceptional case' do
|
|
55
|
-
before do
|
|
56
|
-
expect(EXPORTER.errors).to receive(:increment).with(
|
|
57
|
-
hash_including(labels: {
|
|
58
|
-
operation: "Startback::Audit::Runner::ExceptionalOp",
|
|
59
|
-
startback_version: Startback::VERSION,
|
|
60
|
-
app_version: "1.0"
|
|
61
|
-
})
|
|
62
|
-
)
|
|
63
|
-
expect(EXPORTER.calls).not_to receive(:observe)
|
|
64
|
-
end
|
|
65
|
-
it 'let errors bubble up' do
|
|
66
|
-
expect { Runner.new.test_exp }.to raise_error(/Oops/)
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
end
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'startback/audit'
|
|
3
|
-
module Startback
|
|
4
|
-
module Audit
|
|
5
|
-
describe Trailer do
|
|
6
|
-
|
|
7
|
-
let(:trailer) {
|
|
8
|
-
Trailer.new("/tmp/trail.log")
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
describe "op_name" do
|
|
12
|
-
|
|
13
|
-
def op_name(op, trailer = self.trailer)
|
|
14
|
-
trailer.send(:op_name, op)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
it 'uses op_name in priority if provided' do
|
|
18
|
-
op = OpenStruct.new(op_name: "foo")
|
|
19
|
-
expect(op_name(op)).to eql("foo")
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
describe "op_data" do
|
|
24
|
-
|
|
25
|
-
def op_data(op, trailer = self.trailer)
|
|
26
|
-
trailer.send(:op_data, op)
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
it 'uses op_data in priority if provided' do
|
|
30
|
-
op = OpenStruct.new(op_data: { foo: "bar" }, input: 12, request: 13)
|
|
31
|
-
expect(op_data(op)).to eql({ foo: "bar" })
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
it 'uses to_trail then' do
|
|
35
|
-
op = OpenStruct.new(to_trail: { foo: "bar" }, input: 12, request: 13)
|
|
36
|
-
expect(op_data(op)).to eql({ foo: "bar" })
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
it 'uses input then' do
|
|
40
|
-
op = OpenStruct.new(input: { foo: "bar" }, request: 13)
|
|
41
|
-
expect(op_data(op)).to eql({ foo: "bar" })
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
it 'uses request then' do
|
|
45
|
-
op = OpenStruct.new(request: { foo: "bar" })
|
|
46
|
-
expect(op_data(op)).to eql({ foo: "bar" })
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
it 'applies default blacklists for security reasons' do
|
|
50
|
-
op = OpenStruct.new(input: {
|
|
51
|
-
token: "will not be dumped",
|
|
52
|
-
a_token: "will not be dumped",
|
|
53
|
-
AToken: "will not be dumped",
|
|
54
|
-
password: "will not be dumped",
|
|
55
|
-
secret: "will not be dumped",
|
|
56
|
-
credentials: "will not be dumped",
|
|
57
|
-
foo: "bar"
|
|
58
|
-
})
|
|
59
|
-
expect(op_data(op)).to eql({
|
|
60
|
-
foo: "bar"
|
|
61
|
-
})
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
it 'applies default blacklists to data arrays too' do
|
|
65
|
-
op = OpenStruct.new(input: [{
|
|
66
|
-
token: "will not be dumped",
|
|
67
|
-
a_token: "will not be dumped",
|
|
68
|
-
AToken: "will not be dumped",
|
|
69
|
-
password: "will not be dumped",
|
|
70
|
-
secret: "will not be dumped",
|
|
71
|
-
credentials: "will not be dumped",
|
|
72
|
-
foo: "bar"
|
|
73
|
-
}])
|
|
74
|
-
expect(op_data(op)).to eql([{
|
|
75
|
-
foo: "bar"
|
|
76
|
-
}])
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
it 'uses the stop words provided at construction' do
|
|
80
|
-
t = Trailer.new("/tmp/trail.log", blacklist: "hello and world")
|
|
81
|
-
op = OpenStruct.new(request: { Hello: "bar", World: "foo", foo: "bar" })
|
|
82
|
-
expect(op_data(op, t)).to eql({ foo: "bar" })
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
describe "op_context" do
|
|
88
|
-
|
|
89
|
-
def op_context(op, trailer = self.trailer)
|
|
90
|
-
trailer.send(:op_context, op)
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
it 'applies default blacklists for security reasons' do
|
|
94
|
-
op = OpenStruct.new(context: {
|
|
95
|
-
token: "will not be dumped",
|
|
96
|
-
foo: "bar"
|
|
97
|
-
})
|
|
98
|
-
expect(op_context(op)).to eql({ foo: "bar" })
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
end
|
|
104
|
-
end
|
|
105
|
-
end
|
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'startback/caching/entity_cache'
|
|
3
|
-
require 'startback/caching/store'
|
|
4
|
-
module Startback
|
|
5
|
-
module Caching
|
|
6
|
-
describe EntityCache do
|
|
7
|
-
|
|
8
|
-
class BaseCache < EntityCache
|
|
9
|
-
|
|
10
|
-
def initialize(context = nil)
|
|
11
|
-
super(Store.new, context)
|
|
12
|
-
@called = 0
|
|
13
|
-
@last_key = nil
|
|
14
|
-
end
|
|
15
|
-
attr_reader :called, :last_key
|
|
16
|
-
|
|
17
|
-
protected
|
|
18
|
-
|
|
19
|
-
def primary_key(ckey)
|
|
20
|
-
case ckey
|
|
21
|
-
when Integer then "a key"
|
|
22
|
-
when String then ckey
|
|
23
|
-
else
|
|
24
|
-
raise "Invalid key `#{ckey}`"
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
# We use the deprecated methods below to test
|
|
29
|
-
# backward compatibility with 0.5.0.
|
|
30
|
-
|
|
31
|
-
def full_key(key)
|
|
32
|
-
{ k: key }
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def load_raw_data(key)
|
|
36
|
-
@called += 1
|
|
37
|
-
@last_key = key
|
|
38
|
-
"a value"
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
class ShortCache < BaseCache
|
|
44
|
-
self.default_ttl = 1
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
class InvalidatingCache < BaseCache
|
|
48
|
-
|
|
49
|
-
protected
|
|
50
|
-
|
|
51
|
-
def valid?(key, value)
|
|
52
|
-
false
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
let(:cache) {
|
|
58
|
-
BaseCache.new
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
describe "default_ttl" do
|
|
62
|
-
|
|
63
|
-
it 'has a default ttl of one hour' do
|
|
64
|
-
expect(BaseCache.default_ttl).to eql(3600)
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
it 'allows overriding it' do
|
|
68
|
-
expect(ShortCache.default_ttl).to eql(1)
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
it 'is accessible as default_caching_options on the instance' do
|
|
72
|
-
expect(cache.send(:default_caching_options)).to eql({ttl: 3600})
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
describe "get" do
|
|
78
|
-
|
|
79
|
-
subject{
|
|
80
|
-
cache.get("a key")
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
it 'yields to load_raw_data only once with the short key' do
|
|
84
|
-
expect(subject).to eql("a value")
|
|
85
|
-
expect(subject).to eql("a value")
|
|
86
|
-
expect(cache.called).to eql(1)
|
|
87
|
-
expect(cache.last_key).to eql("a key")
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
describe "primary_key" do
|
|
93
|
-
|
|
94
|
-
subject{
|
|
95
|
-
cache.get(12)
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
it 'allows using candidate keys' do
|
|
99
|
-
expect(subject).to eql("a value")
|
|
100
|
-
expect(subject).to eql("a value")
|
|
101
|
-
expect(cache.called).to eql(1)
|
|
102
|
-
expect(cache.last_key).to eql("a key")
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
describe "invalidate" do
|
|
108
|
-
|
|
109
|
-
it 'strips the key on the store, yielding a cache miss' do
|
|
110
|
-
expect(cache.get("a key")).to eql("a value")
|
|
111
|
-
cache.invalidate("a key")
|
|
112
|
-
expect(cache.get("a key")).to eql("a value")
|
|
113
|
-
expect(cache.called).to eql(2)
|
|
114
|
-
expect(cache.last_key).to eql("a key")
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
describe "valid? override" do
|
|
120
|
-
|
|
121
|
-
let(:cache) {
|
|
122
|
-
InvalidatingCache.new
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
it 'yields to load_raw_data only once with the extend key' do
|
|
126
|
-
expect(cache.get("a key")).to eql("a value")
|
|
127
|
-
expect(cache.get("a key")).to eql("a value")
|
|
128
|
-
expect(cache.called).to eql(2)
|
|
129
|
-
expect(cache.last_key).to eql("a key")
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
end
|
|
135
|
-
end
|
|
136
|
-
end
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
|
|
3
|
-
module Startback
|
|
4
|
-
describe Context, "factor" do
|
|
5
|
-
|
|
6
|
-
let(:context) {
|
|
7
|
-
Context.new
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
class ContextRelatedAbstraction
|
|
11
|
-
|
|
12
|
-
def initialize(context)
|
|
13
|
-
@context = context
|
|
14
|
-
end
|
|
15
|
-
attr_reader :context
|
|
16
|
-
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
class ContextRelatedAbstractionWithArgs
|
|
20
|
-
|
|
21
|
-
def initialize(arg1, arg2, context)
|
|
22
|
-
@arg1 = arg1
|
|
23
|
-
@arg2 = arg2
|
|
24
|
-
@context = context
|
|
25
|
-
end
|
|
26
|
-
attr_reader :arg1, :arg2, :context
|
|
27
|
-
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
it 'is a factory for other context-related abstractions' do
|
|
31
|
-
got = context.factor(ContextRelatedAbstraction)
|
|
32
|
-
expect(got).to be_a(ContextRelatedAbstraction)
|
|
33
|
-
expect(got.context).to be(context)
|
|
34
|
-
|
|
35
|
-
got2 = context.factor(ContextRelatedAbstraction)
|
|
36
|
-
expect(got2).to be(got)
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
it 'is takes cares of abstraction arguments' do
|
|
40
|
-
got = context.factor(ContextRelatedAbstractionWithArgs, 12, 14)
|
|
41
|
-
expect(got).to be_a(ContextRelatedAbstractionWithArgs)
|
|
42
|
-
expect(got.context).to be(context)
|
|
43
|
-
expect(got.arg1).to eql(12)
|
|
44
|
-
expect(got.arg2).to eql(14)
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
it 'is caches even in presence ofabstraction arguments' do
|
|
48
|
-
got = context.factor(ContextRelatedAbstractionWithArgs, 12, 14)
|
|
49
|
-
expect(got).to be_a(ContextRelatedAbstractionWithArgs)
|
|
50
|
-
|
|
51
|
-
got2 = context.factor(ContextRelatedAbstractionWithArgs, 12, 14)
|
|
52
|
-
expect(got2).to be(got)
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
it 'is distinguishes different abstraction arguments' do
|
|
56
|
-
got = context.factor(ContextRelatedAbstractionWithArgs, 12, 14)
|
|
57
|
-
expect(got).to be_a(ContextRelatedAbstractionWithArgs)
|
|
58
|
-
|
|
59
|
-
got2 = context.factor(ContextRelatedAbstractionWithArgs, 17, 14)
|
|
60
|
-
expect(got2).not_to be(got)
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
end
|
|
64
|
-
end
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
|
|
3
|
-
module Startback
|
|
4
|
-
describe Context, "dup" do
|
|
5
|
-
|
|
6
|
-
let(:context) {
|
|
7
|
-
SubContext.new.tap{|s| s.foo = "bar" }
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
class ContextRelatedAbstraction
|
|
11
|
-
|
|
12
|
-
def initialize(context)
|
|
13
|
-
@context = context
|
|
14
|
-
end
|
|
15
|
-
attr_reader :context
|
|
16
|
-
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
it 'yields a dup of the original context' do
|
|
20
|
-
seen = false
|
|
21
|
-
got = context.dup{|x|
|
|
22
|
-
seen = x
|
|
23
|
-
expect(x).not_to be(context)
|
|
24
|
-
}
|
|
25
|
-
expect(seen).to be(got)
|
|
26
|
-
expect(got).to be_a(SubContext)
|
|
27
|
-
expect(got).not_to be(context)
|
|
28
|
-
expect(got.foo).to eql("bar")
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
it 'cleans all factored cache' do
|
|
32
|
-
cra = context.factor(ContextRelatedAbstraction)
|
|
33
|
-
expect(cra).to be_a(ContextRelatedAbstraction)
|
|
34
|
-
cra2 = context.factor(ContextRelatedAbstraction)
|
|
35
|
-
expect(cra2).to be(cra)
|
|
36
|
-
cra3 = context.dup.factor(ContextRelatedAbstraction)
|
|
37
|
-
expect(cra3).not_to be(cra)
|
|
38
|
-
expect(cra3).not_to be(cra2)
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
end
|
|
42
|
-
end
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
|
|
3
|
-
module Startback
|
|
4
|
-
describe Context, "fork" do
|
|
5
|
-
|
|
6
|
-
it 'is a simple dup without args' do
|
|
7
|
-
context = SubContext.new
|
|
8
|
-
context.foo = ['hello']
|
|
9
|
-
|
|
10
|
-
forked = context.fork
|
|
11
|
-
expect(forked).not_to be(context)
|
|
12
|
-
expect(forked.foo).to eql(['hello'])
|
|
13
|
-
expect(forked.foo).to be(context.foo)
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
it 'yields the context if a block is provided' do
|
|
17
|
-
context = SubContext.new
|
|
18
|
-
|
|
19
|
-
seen = false
|
|
20
|
-
context.fork({ 'foo' => 'hello' }) do |forked|
|
|
21
|
-
expect(forked).not_to be(context)
|
|
22
|
-
expect(forked.foo).to eql('hello')
|
|
23
|
-
seen = true
|
|
24
|
-
end
|
|
25
|
-
expect(seen).to eql(true)
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
it 'uses the factory on the hash provided' do
|
|
29
|
-
context = SubContext.new
|
|
30
|
-
|
|
31
|
-
forked = context.fork({ 'foo' => 'hello' })
|
|
32
|
-
expect(forked).not_to be(context)
|
|
33
|
-
expect(forked.foo).to eql('hello')
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
end
|
|
37
|
-
end
|