nestene 0.1.0
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 +15 -0
- data/.gitignore +15 -0
- data/.rspec +1 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +31 -0
- data/Rakefile +2 -0
- data/TODO.txt +7 -0
- data/api.rb +8 -0
- data/autons.rb +13 -0
- data/bin/nestene.rb +5 -0
- data/config.ru +21 -0
- data/features/api/api_create_auton.feature +6 -0
- data/features/api/api_credentials.feature +11 -0
- data/features/api/api_list_of_autons.feature +6 -0
- data/features/callback.feature +13 -0
- data/features/create_auton.feature +11 -0
- data/features/credentials.feature +7 -0
- data/features/execute_step.feature +59 -0
- data/features/restart.feature +7 -0
- data/features/schedule_steps.feature +7 -0
- data/features/step_definitions/api/api_create_auton_steps.rb +16 -0
- data/features/step_definitions/api/api_credentials_steps.rb +22 -0
- data/features/step_definitions/api/api_list_of_autons_steps.rb +8 -0
- data/features/step_definitions/callback_steps.rb +75 -0
- data/features/step_definitions/create_auton_steps.rb +32 -0
- data/features/step_definitions/credentials_steps.rb +24 -0
- data/features/step_definitions/execute_step_steps.rb +177 -0
- data/features/step_definitions/restart_steps.rb +5 -0
- data/features/step_definitions/schedule_steps_steps.rb +29 -0
- data/features/step_definitions/time_delayed_steps_steps.rb +103 -0
- data/features/step_definitions/ui/create_auton_steps.rb +21 -0
- data/features/step_definitions/ui/list_of_autons_steps.rb +18 -0
- data/features/step_definitions/ui/schedule_auton_step_steps.rb +64 -0
- data/features/step_definitions/ui/show_auton_steps.rb +49 -0
- data/features/support/env.rb +36 -0
- data/features/time_delayed_steps.feature +28 -0
- data/features/ui/create_auton.feature +7 -0
- data/features/ui/list_of_autons.feature +7 -0
- data/features/ui/schedule_auton_step.feature +12 -0
- data/features/ui/show_auton.feature +14 -0
- data/lib/nestene/actor/auton_queue.rb +87 -0
- data/lib/nestene/actor/auton_storage.rb +50 -0
- data/lib/nestene/actor/core.rb +150 -0
- data/lib/nestene/actor/delayed_scheduler.rb +76 -0
- data/lib/nestene/auton_context.rb +31 -0
- data/lib/nestene/auton_execution_queue.rb +43 -0
- data/lib/nestene/auton_state.rb +27 -0
- data/lib/nestene/callback.rb +7 -0
- data/lib/nestene/delayed_method.rb +17 -0
- data/lib/nestene/executed_method.rb +29 -0
- data/lib/nestene/executing_method.rb +23 -0
- data/lib/nestene/execution_error.rb +39 -0
- data/lib/nestene/scheduled_method.rb +21 -0
- data/lib/nestene/storage.rb +72 -0
- data/lib/nestene/ui/app.rb +103 -0
- data/lib/nestene/ui/public/app/application.js +75 -0
- data/lib/nestene/ui/public/vendor/angular-ui-sortable/sortable.min.js +1 -0
- data/lib/nestene/ui/public/vendor/angular.min.js +248 -0
- data/lib/nestene/ui/public/vendor/bootstrap/css/bootstrap-theme.css +347 -0
- data/lib/nestene/ui/public/vendor/bootstrap/css/bootstrap-theme.min.css +7 -0
- data/lib/nestene/ui/public/vendor/bootstrap/css/bootstrap.css +5785 -0
- data/lib/nestene/ui/public/vendor/bootstrap/css/bootstrap.min.css +7 -0
- data/lib/nestene/ui/public/vendor/bootstrap/fonts/glyphicons-halflings-regular.eot +0 -0
- data/lib/nestene/ui/public/vendor/bootstrap/fonts/glyphicons-halflings-regular.svg +229 -0
- data/lib/nestene/ui/public/vendor/bootstrap/fonts/glyphicons-halflings-regular.ttf +0 -0
- data/lib/nestene/ui/public/vendor/bootstrap/fonts/glyphicons-halflings-regular.woff +0 -0
- data/lib/nestene/ui/public/vendor/bootstrap/js/bootstrap.js +1951 -0
- data/lib/nestene/ui/public/vendor/bootstrap/js/bootstrap.min.js +6 -0
- data/lib/nestene/ui/public/vendor/jquery-ui.min.js +13 -0
- data/lib/nestene/ui/public/vendor/jquery.bootstrap-growl.min.js +1 -0
- data/lib/nestene/ui/public/vendor/jquery.min.js +5 -0
- data/lib/nestene/ui/public/vendor/json-editor/directives.js +245 -0
- data/lib/nestene/ui/public/vendor/json-editor/styles.css +165 -0
- data/lib/nestene/ui/views/auton.haml +42 -0
- data/lib/nestene/ui/views/auton_form.haml +8 -0
- data/lib/nestene/ui/views/index.haml +35 -0
- data/lib/nestene/ui/views/layout.haml +40 -0
- data/lib/nestene/ui/views/schedule_step.haml +14 -0
- data/lib/nestene/version.rb +3 -0
- data/lib/nestene.rb +50 -0
- data/nestene.gemspec +39 -0
- data/spec/nestene/auton_execution_queue_spec.rb +78 -0
- data/spec/nestene/nestene_spec.rb +137 -0
- data/spec/nestene/storage_spec.rb +125 -0
- data/spec/spec_helper.rb +2 -0
- metadata +373 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
.jumbotron
|
|
2
|
+
%p= @auton_id
|
|
3
|
+
%p
|
|
4
|
+
%span#auton_state.label.label-default= @auton_state.state
|
|
5
|
+
.panel.panel-default
|
|
6
|
+
.panel-heading Actions
|
|
7
|
+
.panel-body
|
|
8
|
+
%a.btn.btn-default#schedule_step{href: url('/auton/%s/schedule_step') % @auton_id} Schedule Step
|
|
9
|
+
|
|
10
|
+
.panel.panel-default
|
|
11
|
+
.panel-heading State
|
|
12
|
+
.panel-body
|
|
13
|
+
%code#current_state{'data-toggle' => "tooltip", 'data-placement' => "left", title:"Tooltip on left"}
|
|
14
|
+
= JSON.pretty_generate(@auton_state.serialized)
|
|
15
|
+
|
|
16
|
+
.panel.panel-default
|
|
17
|
+
#queue.panel-heading Queue
|
|
18
|
+
.panel-body.container-fluid
|
|
19
|
+
.row
|
|
20
|
+
.col-md-12
|
|
21
|
+
.panel.panel-default
|
|
22
|
+
#executing.panel-heading Executing
|
|
23
|
+
.panel-body
|
|
24
|
+
- if @auton_state.queue.currently_executing
|
|
25
|
+
= "%s(%s)" % [@auton_state.queue.currently_executing.name, @auton_state.queue.currently_executing.parameters.join(', ')]
|
|
26
|
+
|
|
27
|
+
.row
|
|
28
|
+
.col-md-6
|
|
29
|
+
#to_execute.panel.panel-default
|
|
30
|
+
.panel-heading To Execute
|
|
31
|
+
.panel-body
|
|
32
|
+
%ul.list-group
|
|
33
|
+
- @auton_state.queue.to_execute.each do |to_execute|
|
|
34
|
+
%li.list-group-item= to_execute.name
|
|
35
|
+
|
|
36
|
+
.col-md-6
|
|
37
|
+
#executed.panel.panel-default
|
|
38
|
+
.panel-heading Executed
|
|
39
|
+
.panel-body
|
|
40
|
+
%ul.list-group
|
|
41
|
+
- @auton_state.queue.executed.each do |executed|
|
|
42
|
+
%li.list-group-item= executed.name
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
.panel.panel-default
|
|
2
|
+
.panel-heading Create New Auton
|
|
3
|
+
.panel-body
|
|
4
|
+
%form{method: 'POST', action: url '/auton/create', role: 'form'}
|
|
5
|
+
.form-group
|
|
6
|
+
%label{for: 'auton_type'}Type
|
|
7
|
+
%input#auton_type.form-control{type: 'text', placeholder: 'Type', name: 'auton_type'}
|
|
8
|
+
%button#create.btn.btn-default{type: 'submit'}Create
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
.panel.panel-default{'ng-app' => 'nestene'}
|
|
2
|
+
.panel-body
|
|
3
|
+
%div#tabs{role: 'tabpanel'}
|
|
4
|
+
%ul.nav.nav-tabs{role: 'tablist'}
|
|
5
|
+
%li.active#running_nav{role: 'presentation'}
|
|
6
|
+
%a.btn.btn-default{href: "#running", 'data-toggle'=>"tab", role: 'tab'} Running Autons
|
|
7
|
+
%li#create_auton_nav{role: 'presentation'}
|
|
8
|
+
%a.btn.btn-default{href: "#create_auton", 'data-toggle'=>"tab", role: 'tab'} Create Auton
|
|
9
|
+
%li#credentials_nav{role: 'presentation'}
|
|
10
|
+
%a.btn.btn-default{href: "#credentials", 'data-toggle'=>"tab", role: 'tab'} Credentials
|
|
11
|
+
%div.tab-content
|
|
12
|
+
%div.tab-pane.active.fade.in#running{'ng-controller' => 'AutonsController'}
|
|
13
|
+
%ul.list-group#auton_list
|
|
14
|
+
%li.list-group-item{'ng-repeat' => 'autonName in autons'}
|
|
15
|
+
%a.btn{'ng-href' => url('/auton/{{autonName}}')} {{autonName}}
|
|
16
|
+
%div.tab-pane.fade#create_auton{'ng-controller' => 'CreateAutonFormController'}
|
|
17
|
+
.panel.panel-default
|
|
18
|
+
.panel-heading Create New Auton
|
|
19
|
+
.panel-body
|
|
20
|
+
%form{role: 'form'}
|
|
21
|
+
.form-group
|
|
22
|
+
%label{for: 'auton_type'} Auton Type
|
|
23
|
+
%input#auton_type.form-control{type: 'text', placeholder: 'Type', 'ng-model' => 'autonType', 'required' => true}
|
|
24
|
+
%button#create.btn.btn-default{type: 'submit', 'ng-click' => 'createAuton()'}Create
|
|
25
|
+
%div.tab-pane.fade#credentials{'ng-controller' => 'CredentialsController'}
|
|
26
|
+
.panel.panel-default
|
|
27
|
+
.panel-heading Current Credentials
|
|
28
|
+
.panel-body
|
|
29
|
+
.jsonView
|
|
30
|
+
%json{child: "credentials", 'default-collapsed'=>"false", type: "object"}
|
|
31
|
+
%button.btn.btn-default{'ng-click' => 'storeCredentials()'} Save
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
!!!
|
|
2
|
+
%html
|
|
3
|
+
%head
|
|
4
|
+
%title Nestene
|
|
5
|
+
%meta{:content => "width=device-width, initial-scale=1.0", :name => "viewport"}
|
|
6
|
+
/ Bootstrap
|
|
7
|
+
%link{:href => "/vendor/bootstrap/css/bootstrap.min.css", :rel => "stylesheet"}
|
|
8
|
+
%link{:href => "/vendor/json-editor/styles.css", :rel => "stylesheet"}
|
|
9
|
+
/ HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries
|
|
10
|
+
/ WARNING: Respond.js doesn't work if you view the page via file://
|
|
11
|
+
/[if lt IE 9]
|
|
12
|
+
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
|
|
13
|
+
<script src="https://oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
|
|
14
|
+
%body
|
|
15
|
+
.container
|
|
16
|
+
/ Static navbar
|
|
17
|
+
.navbar.navbar-default{:role => "navigation"}
|
|
18
|
+
.navbar-header
|
|
19
|
+
%button.navbar-toggle{"data-target" => ".navbar-collapse", "data-toggle" => "collapse", :type => "button"}
|
|
20
|
+
%span.sr-only Toggle navigation
|
|
21
|
+
%span.icon-bar
|
|
22
|
+
%span.icon-bar
|
|
23
|
+
%span.icon-bar
|
|
24
|
+
%a.navbar-brand{:href => "/"} Nestene
|
|
25
|
+
%ol.breadcrumb
|
|
26
|
+
- (@position || [{link: '/', name: 'Home'}]).each do |crumb|
|
|
27
|
+
%li
|
|
28
|
+
%a.btn.btn-default.btn-xs{href: crumb[:link]}=crumb[:name]
|
|
29
|
+
%div
|
|
30
|
+
- if @error then
|
|
31
|
+
.alert.alert-error= @error
|
|
32
|
+
= yield
|
|
33
|
+
%script{:src => "/vendor/jquery.min.js"}
|
|
34
|
+
%script{:src => "/vendor/jquery-ui.min.js"}
|
|
35
|
+
%script{:src => "/vendor/angular.min.js"}
|
|
36
|
+
%script{:src => "/vendor/bootstrap/js/bootstrap.min.js"}
|
|
37
|
+
%script{:src => "/vendor/jquery.bootstrap-growl.min.js"}
|
|
38
|
+
%script{:src => "/vendor/angular-ui-sortable/sortable.min.js"}
|
|
39
|
+
%script{:src => "/vendor/json-editor/directives.js"}
|
|
40
|
+
%script{:src => "/app/application.js"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
.panel.panel-default
|
|
2
|
+
.panel-heading Schedule Step for #{@auton_id}
|
|
3
|
+
.panel-body
|
|
4
|
+
%form{method: 'POST', action: '/auton/%s/schedule_step' % @auton_id, role: 'form'}
|
|
5
|
+
.form-group
|
|
6
|
+
%label{for: 'step_name'}Step Name
|
|
7
|
+
%select.form-control{name: 'step_name'}
|
|
8
|
+
- @available_methods.each do |method|
|
|
9
|
+
%option{value: method.name, selected: @step_name == method.name.to_s}= method.name
|
|
10
|
+
.form-group
|
|
11
|
+
%label{for: 'step_name'} Parameters
|
|
12
|
+
- (0 .. @number_of_params - 1).each do |index|
|
|
13
|
+
%input.form-control{name: 'parameters[%d]' % index, type: 'text'}
|
|
14
|
+
%button#schedule.btn.btn-default{type: 'submit'}Schedule
|
data/lib/nestene.rb
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
require 'structure_mapper'
|
|
2
|
+
require 'securerandom'
|
|
3
|
+
require 'celluloid'
|
|
4
|
+
require 'celluloid/autostart'
|
|
5
|
+
require 'nestene/storage'
|
|
6
|
+
require 'nestene/actor/delayed_scheduler'
|
|
7
|
+
require 'nestene/actor/core'
|
|
8
|
+
require 'nestene/actor/auton_storage'
|
|
9
|
+
require 'nestene/actor/auton_queue'
|
|
10
|
+
require 'nestene/auton_context'
|
|
11
|
+
require 'nestene/callback'
|
|
12
|
+
require 'nestene/scheduled_method'
|
|
13
|
+
require 'nestene/executing_method'
|
|
14
|
+
require 'nestene/execution_error'
|
|
15
|
+
require 'nestene/executed_method'
|
|
16
|
+
require 'nestene/auton_execution_queue'
|
|
17
|
+
require 'nestene/auton_state'
|
|
18
|
+
require 'nestene/ui/app'
|
|
19
|
+
|
|
20
|
+
module Nestene
|
|
21
|
+
|
|
22
|
+
class SelfValue
|
|
23
|
+
def value
|
|
24
|
+
self
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.class_from_string(name)
|
|
29
|
+
name.split('::').inject(Object) do |mod, class_name|
|
|
30
|
+
mod.const_get(class_name) or raise "Could not find class #{name}"
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def self.start_nestene(storage)
|
|
35
|
+
Celluloid::Actor[:nestene_core] = Nestene::Actor::Core.new(storage)
|
|
36
|
+
Celluloid::Actor[:auton_queue] = Nestene::Actor::AutonQueue.new
|
|
37
|
+
Celluloid::Actor[:delayed_scheduler] = Nestene::Actor::DelayedScheduler.new
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
class Time
|
|
43
|
+
def self.from_structure str
|
|
44
|
+
str ? iso8601(str) : nil
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def to_structure
|
|
48
|
+
iso8601(3)
|
|
49
|
+
end
|
|
50
|
+
end
|
data/nestene.gemspec
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require 'nestene/version'
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = "nestene"
|
|
8
|
+
spec.version = Nestene::VERSION
|
|
9
|
+
spec.authors = ["Dragan Milic"]
|
|
10
|
+
spec.email = ["dragan@netice9.com"]
|
|
11
|
+
spec.summary = %q{Nestene Automation Framework}
|
|
12
|
+
spec.description = %q{Nestene Automation Framework}
|
|
13
|
+
spec.homepage = ""
|
|
14
|
+
spec.license = "MIT"
|
|
15
|
+
|
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
19
|
+
spec.require_paths = ["lib"]
|
|
20
|
+
|
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
|
22
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
|
23
|
+
|
|
24
|
+
spec.add_development_dependency "cucumber"
|
|
25
|
+
spec.add_development_dependency "rspec"
|
|
26
|
+
spec.add_development_dependency "pry"
|
|
27
|
+
spec.add_development_dependency "pry-debugger"
|
|
28
|
+
spec.add_development_dependency "timecop"
|
|
29
|
+
spec.add_development_dependency "capybara"
|
|
30
|
+
spec.add_development_dependency "rack-test"
|
|
31
|
+
spec.add_development_dependency "poltergeist"
|
|
32
|
+
|
|
33
|
+
spec.add_dependency "sinatra"
|
|
34
|
+
spec.add_dependency "celluloid"
|
|
35
|
+
spec.add_dependency "structure_mapper"
|
|
36
|
+
spec.add_dependency "haml"
|
|
37
|
+
spec.add_dependency "puma"
|
|
38
|
+
|
|
39
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'timecop'
|
|
3
|
+
|
|
4
|
+
module Nestene
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
describe AutonExecutionQueue do
|
|
8
|
+
|
|
9
|
+
before do
|
|
10
|
+
Timecop.freeze(Time.local(1990))
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
after do
|
|
14
|
+
Timecop.return
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
describe '#remove_delayed_method' do
|
|
18
|
+
context "when the delayed method has been scheduled" do
|
|
19
|
+
let (:delayed_method_uuid) {subject.add_delayed_method(:some_method, ['p1','p2'], 0.3).uuid}
|
|
20
|
+
|
|
21
|
+
it "should remove the delayed method" do
|
|
22
|
+
uuid = delayed_method_uuid
|
|
23
|
+
subject.remove_delayed_method(uuid)
|
|
24
|
+
|
|
25
|
+
expect(subject.delayed).to be_empty
|
|
26
|
+
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
describe '#add_delayed_method' do
|
|
33
|
+
|
|
34
|
+
let(:every) { nil }
|
|
35
|
+
|
|
36
|
+
before {subject.add_delayed_method :some_method, ['p1','p2'], 0.3, every}
|
|
37
|
+
|
|
38
|
+
it "should add a delayed method" do
|
|
39
|
+
expect(subject.delayed).to_not be_empty
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "should assign proper execute_at to delayed method" do
|
|
43
|
+
expect(subject.delayed.first.execute_at).to eq(Time.now + 0.3)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it "should assign uuid to delayed method" do
|
|
47
|
+
expect(subject.delayed.first.uuid).to_not be_nil
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it "should assign scheduled_at to delayed method" do
|
|
51
|
+
expect(subject.delayed.first.scheduled_at).to eq(Time.now)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "should assign parameters to delayed method" do
|
|
55
|
+
expect(subject.delayed.first.parameters).to eq(["p1", "p2"])
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
it "should sort delayed methods by their execute_at times in ascending order" do
|
|
60
|
+
subject.add_delayed_method :sooner_method, ['p1','p2'], 0.1
|
|
61
|
+
|
|
62
|
+
expect(subject.delayed.first.name).to eq(:sooner_method)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
context "when every is not nil" do
|
|
66
|
+
|
|
67
|
+
let(:every) { 0.5 }
|
|
68
|
+
|
|
69
|
+
it "should set every value" do
|
|
70
|
+
expect(subject.delayed.first.every).to eq(every)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'timecop'
|
|
3
|
+
|
|
4
|
+
module Nestene
|
|
5
|
+
|
|
6
|
+
describe ScheduledMethod do
|
|
7
|
+
describe '#new' do
|
|
8
|
+
context "when DelayedMethod is passed as parameter" do
|
|
9
|
+
|
|
10
|
+
let(:delayed_method) do
|
|
11
|
+
method = DelayedMethod.new
|
|
12
|
+
method.name = :some_method
|
|
13
|
+
method.parameters = ['p1','p2']
|
|
14
|
+
method.uuid = 'some_uuid'
|
|
15
|
+
method.scheduled_at = Time.now
|
|
16
|
+
method
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
subject {described_class.new(delayed_method)}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
it "should copy method's uuid" do
|
|
23
|
+
expect(subject.uuid).to eq(delayed_method.uuid)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "should copy name" do
|
|
27
|
+
expect(subject.name).to eq(delayed_method.name)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "should copy parameters" do
|
|
31
|
+
expect(subject.parameters).to eq(delayed_method.parameters)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
describe ExecutingMethod do
|
|
40
|
+
describe :new do
|
|
41
|
+
context "when ScheduledMethod is passed as parameter" do
|
|
42
|
+
let (:callback) {Callback.new}
|
|
43
|
+
let (:scheduled) do
|
|
44
|
+
scheduled = ScheduledMethod.new
|
|
45
|
+
scheduled.callback = callback
|
|
46
|
+
scheduled
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
subject {ExecutingMethod.new(scheduled)}
|
|
50
|
+
|
|
51
|
+
it "should copy callback" do
|
|
52
|
+
expect(subject.callback).to eq(callback)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
describe ExecutedMethod do
|
|
60
|
+
describe :new do
|
|
61
|
+
context "when ExecutingMethod is passed as parameter" do
|
|
62
|
+
let (:callback) {Callback.new}
|
|
63
|
+
let (:executed) do
|
|
64
|
+
executed = ExecutingMethod.new
|
|
65
|
+
executed.callback = callback
|
|
66
|
+
executed.started_at = Time.now
|
|
67
|
+
executed
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
subject {ExecutedMethod.new(executed)}
|
|
71
|
+
|
|
72
|
+
it "should copy callback" do
|
|
73
|
+
expect(subject.callback).to eq(callback)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
describe ExecutionError do
|
|
80
|
+
|
|
81
|
+
let(:exception) do
|
|
82
|
+
begin
|
|
83
|
+
raise Exception, "some message"
|
|
84
|
+
rescue Exception => e
|
|
85
|
+
e
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
context "when no error is passed to constructur" do
|
|
90
|
+
it "should have nil messsage" do
|
|
91
|
+
expect(subject.message).to be_nil
|
|
92
|
+
end
|
|
93
|
+
it "should have nil type" do
|
|
94
|
+
expect(subject.type).to be_nil
|
|
95
|
+
end
|
|
96
|
+
it "should have nil backtrace" do
|
|
97
|
+
expect(subject.backtrace).to be_nil
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
context 'when error is passed to constructor' do
|
|
102
|
+
subject { described_class.new(exception) }
|
|
103
|
+
|
|
104
|
+
it "should have message set" do
|
|
105
|
+
expect(subject.message).to eq('some message')
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
it "should have type set" do
|
|
109
|
+
expect(subject.type).to eq('Exception')
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
it "should have backtrace set" do
|
|
113
|
+
expect(subject.backtrace).not_to be_empty
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
describe :to_exception do
|
|
119
|
+
subject { ExecutionError.new(exception).to_exception }
|
|
120
|
+
|
|
121
|
+
it "should create" do
|
|
122
|
+
expect(subject).to be_a(Exception)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
it "should create exception with the stored messsage" do
|
|
126
|
+
expect(subject.message).to eq("some message")
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
it "should create exception with a backtrace" do
|
|
130
|
+
expect(subject.backtrace).not_to be_empty
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Nestene
|
|
4
|
+
|
|
5
|
+
describe FileNameConverter do
|
|
6
|
+
describe '#key_to_file_name' do
|
|
7
|
+
it "should convert non-charater in the file name to hex-escaped version" do
|
|
8
|
+
expect(subject.key_to_file_name('test_-+/')).to eq('test_5f_2d_2b_2f')
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
describe '#file_name_to_key' do
|
|
14
|
+
it "should convert hex-escaped version of the file name to the original" do
|
|
15
|
+
expect(subject.file_name_to_key('test_5f_2d_2b_2f')).to eq('test_-+/')
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe DiskStorage do
|
|
21
|
+
|
|
22
|
+
let(:tmpdir) {Dir.mktmpdir}
|
|
23
|
+
|
|
24
|
+
after{FileUtils.remove_entry_secure tmpdir}
|
|
25
|
+
|
|
26
|
+
describe :list do
|
|
27
|
+
|
|
28
|
+
subject {DiskStorage.new(tmpdir)}
|
|
29
|
+
|
|
30
|
+
context "when there is nothing in the storage" do
|
|
31
|
+
it "should return empty list" do
|
|
32
|
+
expect(subject.list).to eq([])
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
context "when there is at least one object in the storage" do
|
|
37
|
+
before {subject.store("test",{})}
|
|
38
|
+
|
|
39
|
+
it "should return list of existing objects" do
|
|
40
|
+
expect(subject.list).to eq(['test'])
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
describe :load do
|
|
46
|
+
|
|
47
|
+
subject {DiskStorage.new(tmpdir)}
|
|
48
|
+
|
|
49
|
+
context "when the object does not exist" do
|
|
50
|
+
it "should return nil" do
|
|
51
|
+
expect(subject.load('whatever')).to be_nil
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
context "when the object exists" do
|
|
56
|
+
before {subject.store('test',{})}
|
|
57
|
+
it "should return object's structure" do
|
|
58
|
+
expect(subject.load('test')).to eq({})
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
describe :store do
|
|
65
|
+
subject {DiskStorage.new(tmpdir)}
|
|
66
|
+
|
|
67
|
+
it "stores structure" do
|
|
68
|
+
subject.store('test',{})
|
|
69
|
+
expect(subject.load('test')).to eq({})
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
describe MemoryStorage do
|
|
76
|
+
describe :list do
|
|
77
|
+
|
|
78
|
+
subject {MemoryStorage.new}
|
|
79
|
+
|
|
80
|
+
context "when there is nothing in the storage" do
|
|
81
|
+
it "should return empty list" do
|
|
82
|
+
expect(subject.list).to eq([])
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
context "when there is at least one object in the storage" do
|
|
87
|
+
before {subject.store("test",{})}
|
|
88
|
+
|
|
89
|
+
it "should return list of existing objects" do
|
|
90
|
+
expect(subject.list).to eq(['test'])
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
describe :load do
|
|
96
|
+
|
|
97
|
+
subject {MemoryStorage.new}
|
|
98
|
+
|
|
99
|
+
context "when the object does not exist" do
|
|
100
|
+
it "should return nil" do
|
|
101
|
+
expect(subject.load('whatever')).to be_nil
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
context "when the object exists" do
|
|
106
|
+
before {subject.store('test',{})}
|
|
107
|
+
it "should return object's structure" do
|
|
108
|
+
expect(subject.load('test')).to eq({})
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
describe :store do
|
|
116
|
+
subject {MemoryStorage.new}
|
|
117
|
+
|
|
118
|
+
it "stores structure" do
|
|
119
|
+
subject.store('test',{})
|
|
120
|
+
expect(subject.load('test')).to eq({})
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
end
|
|
125
|
+
end
|
data/spec/spec_helper.rb
ADDED