turbogenerator 0.3.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ YjRmMzhkMTA0NGI3NTc1M2E5YTBmMGY0NzVmZjQ3MTFlY2MxNTUzYQ==
5
+ data.tar.gz: !binary |-
6
+ YzZiMDk1ODFiZWJlZTBiNTI0ZmYyYzQwMmYxYmQyYWUzOThmNjQ1Yg==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ NTlmZGVmNTNmMWM3Yjg4ZjU0NDU2ODFlMDQ4MjI5NTA5MDE5NTBiNWE1NGU0
10
+ NDk2MmZkNTRhNzFmZGQ1MTZiZDM5NDNjZjE0MjM1ODE0MTdmYWQ3MmEwMDk0
11
+ ZjA2OGNmYWE4YjBkMWY1NzI2ZjhkNjk3M2M1NzI5MjMwNzA1NWE=
12
+ data.tar.gz: !binary |-
13
+ ZDM4OTMxZDM2NzUwNmVlZjUyODQ4OTc4OTc1Y2I5ZWE0ZWJjZTA5ZjIzNWM3
14
+ ZjQwYmNlYzBhZTZlYTcwZWExZTY2ODM0ZTRkNDUwOTFhNjczZmE0MjVjMDM1
15
+ NjUxZWI1ZWRmNjI2NTJjMjhkMmU5OTM4NWFiZDJjZGRlNzYzOTM=
data/bin/turbo CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require "thor"
4
+ require 'term/ansicolor'
4
5
  require "turbo"
5
6
 
6
7
  def get_real_path(path)
@@ -13,7 +14,7 @@ class TurboApp < Thor
13
14
  def generate(name)
14
15
 
15
16
  if File.exist? "workflows/#{name}"
16
- puts "workflow #{name} has already exist under workflows/#{name}"
17
+ puts "workflow #{name.green} has already exist under workflows/#{name}"
17
18
  return
18
19
  end
19
20
 
@@ -32,7 +33,8 @@ class TurboApp < Thor
32
33
 
33
34
  FileUtils.copy File.join(File.dirname(File.expand_path(__FILE__)), "../lib/templates/workflow.json"), "workflows/#{name}/workflow.json"
34
35
 
35
- puts "workflow #{name} is generated under workflows/#{name}"
36
+ puts "Workflow `#{name.green}` is generated under workflows/#{name}"
37
+ puts "Run `turbo start #{name.green}` to start the workflow"
36
38
  end
37
39
 
38
40
  desc "start", "specify the workflow name"
@@ -40,9 +42,24 @@ class TurboApp < Thor
40
42
  def start(workflow)
41
43
  config = options[:config]
42
44
  turbo = Turbo.new(config)
45
+
46
+ if(!File.exist?("workflows/#{workflow}/workflow.json"))
47
+ puts "Workflow `#{workflow.green}` does not exist"
48
+ puts "Run `turbo generate #{workflow.green}` to generate it first"
49
+ return
50
+ end
51
+
43
52
  turbo.run_workflow(workflow)
44
53
  end
45
54
 
55
+ desc "list", "list all workflows"
56
+ def list
57
+ if(File.exist?("workflows"))
58
+ system ('ls workflows/')
59
+ else
60
+ puts "No workflow found, you can generate one by using `turob generate my-workflow`"
61
+ end
62
+ end
46
63
  end
47
64
 
48
65
  TurboApp.start
data/lib/commander.rb ADDED
@@ -0,0 +1,93 @@
1
+ require 'erb'
2
+ require 'json'
3
+ require 'hashugar'
4
+ require 'jsonpath'
5
+
6
+ require 'term/ansicolor'
7
+
8
+ require 'rexml/document'
9
+ include REXML
10
+
11
+ require 'value_object'
12
+
13
+
14
+ class String
15
+ include Term::ANSIColor
16
+ end
17
+
18
+ def verfiy_xpath(caze, result)
19
+ xmldoc = Document.new(result)
20
+ nodes = XPath.match(xmldoc, "#{caze.success.content}")
21
+
22
+ if nodes != nil
23
+ puts "Case: ['#{caze.name}'] passed".green
24
+ else
25
+ puts "Case: ['#{caze.name}'] failed\nExpected: #{caze.success.content}\nGot: #{result}".red
26
+ end
27
+ puts "#{caze.type} #{caze.url}\n".cyan
28
+ end
29
+
30
+ def verify_regexp(caze, result)
31
+ x = result.match(/#{caze.success.content}/)
32
+
33
+ if x != nil
34
+ puts "Case: ['#{caze.name}'] passed".green
35
+ else
36
+ puts "Case: ['#{caze.name}'] failed\nExpected: #{caze.success.content}\nGot: #{result}".red
37
+ end
38
+ puts "#{caze.type} #{caze.url}\n".cyan
39
+ end
40
+
41
+ def verify_jsonpath(caze, result)
42
+ nodes = JsonPath.on(result, "#{caze.success.content}")
43
+
44
+ if nodes.size != 0
45
+ puts "Case: ['#{caze.name}'] passed".green
46
+ else
47
+ puts "Case: ['#{caze.name}'] failed\nExpected: #{nodes}\nGot: #{result}".red
48
+ end
49
+ puts "#{caze.type} #{caze.url}\n".cyan
50
+ end
51
+
52
+ def verify(caze)
53
+ result = `#{caze.command}`
54
+
55
+ case caze.success.type
56
+ when 'xpath'
57
+ verfiy_xpath(caze, result)
58
+ when 'regexp'
59
+ verify_regexp(caze, result)
60
+ when 'jsonpath'
61
+ verify_jsonpath(caze, result)
62
+ end
63
+ end
64
+
65
+ def generate_command(config)
66
+ template = File.read(File.join(File.dirname(File.expand_path(__FILE__)), 'templates/command.erb'))
67
+ renderer = ERB.new(template)
68
+
69
+ puts "Scenario: #{config.name}, test cases: #{config.cases.size}\n".cyan
70
+ config.cases.each do |caze|
71
+ test_case = TestCase.new({
72
+ :name => caze.name,
73
+ :url => "#{config.baseurl}/#{caze.path}",
74
+ :headers => caze.headers,
75
+ :type => caze.type,
76
+ :data_path => caze.data,
77
+ :success => SuccessDefinition.new(caze.success),
78
+ :debug => caze.debug
79
+ })
80
+
81
+ command = renderer.result(test_case.get_binding).gsub("\n", " ").strip
82
+
83
+ test = ExecutableTest.new({
84
+ :name => caze.name,
85
+ :type => caze.type,
86
+ :url => "#{config.baseurl}/#{caze.path}",
87
+ :command => command,
88
+ :success => SuccessDefinition.new(caze.success)
89
+ })
90
+
91
+ verify(test)
92
+ end
93
+ end
@@ -0,0 +1,18 @@
1
+ module HashRecursiveMerge
2
+ def rmerge!(other_hash)
3
+ merge!(other_hash) do |key, oldval, newval|
4
+ oldval.class == self.class ? oldval.rmerge!(newval) : newval
5
+ end
6
+ end
7
+
8
+ def rmerge(other_hash)
9
+ r = {}
10
+ merge(other_hash) do |key, oldval, newval|
11
+ r[key] = oldval.class == self.class ? oldval.rmerge(newval) : newval
12
+ end
13
+ end
14
+ end
15
+
16
+ class Hash
17
+ include HashRecursiveMerge
18
+ end
@@ -0,0 +1,18 @@
1
+ curl -s
2
+ <% if success.part == "header" %> -D - -o /dev/null<% end %>
3
+
4
+ -X <%= type %>
5
+
6
+ <% if ['POST', 'PUT'].include? type %>
7
+ --data @<%= data_path %>
8
+ <% end %>
9
+
10
+ <% headers.each_pair do |key, value| %>
11
+ --header <%= key %>=<%= value %>
12
+ <% end %>
13
+
14
+ <%= url %>
15
+
16
+ <% if debug %>
17
+ -D - -o debug.log
18
+ <% end %>
@@ -0,0 +1,8 @@
1
+ <% if nodes != nil %>
2
+ Case: ["<%= caze.name %>"] passed
3
+ <% else %>
4
+ Case: ["<%= caze.name %>"] failed
5
+ Expected: <%= caze.success.content %>
6
+ Got: <%= result %>
7
+ <% end %>
8
+ <%= caze.type %> <%= caze.url %>
@@ -1,14 +1,28 @@
1
1
  {
2
- "baseurl": "http://localhost:9527",
3
- "method": "GET",
2
+ "name": "posts",
3
+ "baseurl": "http://localhost:8080",
4
4
  "headers": {
5
5
  "Accept": "application/json",
6
6
  "Content-Type": "application/json"
7
7
  },
8
8
  "cases": [
9
- {
10
- "path": "/resource",
11
- "success": "200 OK"
9
+ { "name": "list posts",
10
+ "path": "/api/feeds",
11
+ "success": {
12
+ "part": "body",
13
+ "type": "jsonpath",
14
+ "content": "$[0].url"
15
+ }
16
+ },
17
+ { "name": "create posts",
18
+ "path": "/api/fav-feeds",
19
+ "type": "POST",
20
+ "data": "resource.json",
21
+ "success": {
22
+ "part": "header",
23
+ "type": "regexp",
24
+ "content": "200 OK"
25
+ }
12
26
  }
13
27
  ]
14
28
  }
data/lib/turbo.rb CHANGED
@@ -2,31 +2,12 @@
2
2
 
3
3
  require 'json'
4
4
  require 'term/ansicolor'
5
+ require 'hashugar'
6
+ require 'rexml/document'
7
+ include REXML
5
8
 
6
- # Author:: Simone Carletti <weppos@weppos.net>
7
- # Copyright:: 2007-2008 The Authors
8
- # License:: MIT License
9
- # Link:: http://www.simonecarletti.com/
10
- # Source:: http://gist.github.com/gists/6391/
11
- #
12
- module HashRecursiveMerge
13
- def rmerge!(other_hash)
14
- merge!(other_hash) do |key, oldval, newval|
15
- oldval.class == self.class ? oldval.rmerge!(newval) : newval
16
- end
17
- end
18
-
19
- def rmerge(other_hash)
20
- r = {}
21
- merge(other_hash) do |key, oldval, newval|
22
- r[key] = oldval.class == self.class ? oldval.rmerge(newval) : newval
23
- end
24
- end
25
- end
26
-
27
- class Hash
28
- include HashRecursiveMerge
29
- end
9
+ require 'hash_recursive'
10
+ require 'commander'
30
11
 
31
12
  class String
32
13
  include Term::ANSIColor
@@ -46,23 +27,25 @@ class Turbo
46
27
  @workflow_path = "workflows/#{workflow}"
47
28
  @pre_command = "#{@workflow_path}/#{wf['before']}"
48
29
  @post_command = "#{@workflow_path}/#{wf['after']}"
30
+ @debug_file = 'debug.log'
49
31
 
50
32
  scenarios = wf['scenarios']
33
+ @run_success = 0
34
+ @run_failed = 0
51
35
 
52
- before
36
+ execute_before_script
53
37
  scenarios.each do |scenario|
54
38
  run_scenario("#{@workflow_path}/scenarios/#{scenario}")
55
39
  end
56
- after
57
-
40
+ execute_after_script
58
41
  end
59
42
 
60
43
  private
61
- def before
44
+ def execute_before_script
62
45
  system "#{@pre_command}"
63
46
  end
64
47
 
65
- def after
48
+ def execute_after_script
66
49
  system "#{@post_command}"
67
50
  end
68
51
 
@@ -76,14 +59,6 @@ class Turbo
76
59
  end
77
60
  end
78
61
 
79
- def generate_header(obj)
80
- headers = []
81
- obj.each_pair do |k, v|
82
- headers << "-H \"#{k}: #{v}\""
83
- end
84
- headers.join(' ')
85
- end
86
-
87
62
  def load_common
88
63
  JSON.parse(File.read(@conf['conf_path'] + '/' + @conf['common_conf']))
89
64
  end
@@ -92,39 +67,18 @@ class Turbo
92
67
  JSON.parse(File.read(scenario))
93
68
  end
94
69
 
95
- def run_scenario(scenario)
96
- common = load_common
97
- config = common.rmerge(load_scenario(scenario))
70
+ def bootstrap(scenario)
71
+ config = load_common.rmerge(load_scenario(scenario)).to_hashugar
98
72
 
99
- if config['disabled']
100
- puts "skipping scenario, #{scenario}".cyan
101
- return
102
- end
103
-
104
- # generate all headers
105
- headers = generate_header(config['headers'])
106
-
107
- # generate HTTP method
108
- method = "-X #{config['method']}"
109
-
110
- # run each case here
111
- config['cases'].each do |caze|
112
- path = config['baseurl'] + caze['path']
113
- data = config['method'] == "POST" || config['method'] == "PUT" ? "-d @#{@workflow_path}/#{caze['data']}" : ""
114
-
115
- debug = @conf['debug'] == 'true' || config['debug'] == 'true' ? "-D - -o debug.log" : ""
73
+ def config.get_binding
74
+ binding
75
+ end
116
76
 
117
- real_command = "curl -is #{headers} #{method} #{data} #{path} #{debug}"
118
- puts real_command
119
- command = "#{real_command} | grep --color=auto -E \"#{caze['success']}\""
77
+ config
78
+ end
120
79
 
121
- ret = system(command)
80
+ def run_scenario(scenario)
81
+ generate_command(bootstrap(scenario))
82
+ end
122
83
 
123
- if ret
124
- puts "#{'Success'}: #{real_command}".green
125
- else
126
- puts "#{'Error'}: #{real_command}".red
127
- end
128
- end
129
- end
130
84
  end
@@ -0,0 +1,52 @@
1
+ require 'ostruct'
2
+
3
+ class TestCase
4
+ attr_accessor :name, :url, :headers, :type, :data_path, :debug, :success
5
+
6
+ def initialize(args)
7
+ obj = OpenStruct.new(args)
8
+ @name = obj.name
9
+ @url = obj.url
10
+ @headers = obj.headers || {}
11
+ @type = obj.type || "GET"
12
+ @data_path = obj.data_path
13
+ @success = obj.success
14
+ @debug = obj.debug
15
+ end
16
+
17
+ def get_binding
18
+ binding
19
+ end
20
+ end
21
+
22
+ class SuccessDefinition
23
+ attr_accessor :part, :type, :content
24
+
25
+ def initialize(args)
26
+ obj = OpenStruct.new(args)
27
+ @part = obj.part
28
+ @type = obj.type
29
+ @content = obj.content
30
+ end
31
+
32
+ def get_binding
33
+ binding
34
+ end
35
+ end
36
+
37
+ class ExecutableTest
38
+ attr_accessor :name, :type, :url, :command, :success
39
+
40
+ def initialize(args)
41
+ obj = OpenStruct.new(args)
42
+ @name = obj.name
43
+ @url = obj.url
44
+ @type = obj.type || "GET"
45
+ @command = obj.command
46
+ @success = obj.success
47
+ end
48
+
49
+ def get_binding
50
+ binding
51
+ end
52
+ end
metadata CHANGED
@@ -1,91 +1,143 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: turbogenerator
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
5
- prerelease:
4
+ version: 0.5.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Juntao Qiu
8
+ - Jia Wei
9
+ - Shen Tong
10
+ - Yan Yu
11
+ - Yang Mengmeng
9
12
  autorequire:
10
13
  bindir: bin
11
14
  cert_chain: []
12
- date: 2014-03-06 00:00:00.000000000 Z
15
+ date: 2015-03-12 00:00:00.000000000 Z
13
16
  dependencies:
14
17
  - !ruby/object:Gem::Dependency
15
18
  name: thor
16
19
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
20
  requirements:
21
+ - - ~>
22
+ - !ruby/object:Gem::Version
23
+ version: '0.18'
19
24
  - - ! '>='
20
25
  - !ruby/object:Gem::Version
21
26
  version: 0.18.1
22
27
  type: :runtime
23
28
  prerelease: false
24
29
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
30
  requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '0.18'
27
34
  - - ! '>='
28
35
  - !ruby/object:Gem::Version
29
36
  version: 0.18.1
30
37
  - !ruby/object:Gem::Dependency
31
38
  name: term-ansicolor
32
39
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
40
  requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: '1.3'
35
44
  - - ! '>='
36
45
  - !ruby/object:Gem::Version
37
46
  version: 1.3.0
38
47
  type: :runtime
39
48
  prerelease: false
40
49
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
50
  requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '1.3'
43
54
  - - ! '>='
44
55
  - !ruby/object:Gem::Version
45
56
  version: 1.3.0
46
- description: turbo is a curl wrapper for make test based on HTTP (aka RESTFul App)
47
- easier
57
+ - !ruby/object:Gem::Dependency
58
+ name: hashugar
59
+ requirement: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ~>
62
+ - !ruby/object:Gem::Version
63
+ version: '1.0'
64
+ - - ! '>='
65
+ - !ruby/object:Gem::Version
66
+ version: 1.0.0
67
+ type: :runtime
68
+ prerelease: false
69
+ version_requirements: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ~>
72
+ - !ruby/object:Gem::Version
73
+ version: '1.0'
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: 1.0.0
77
+ - !ruby/object:Gem::Dependency
78
+ name: jsonpath
79
+ requirement: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ~>
82
+ - !ruby/object:Gem::Version
83
+ version: '0.5'
84
+ - - ! '>='
85
+ - !ruby/object:Gem::Version
86
+ version: 0.5.7
87
+ type: :runtime
88
+ prerelease: false
89
+ version_requirements: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ version: '0.5'
94
+ - - ! '>='
95
+ - !ruby/object:Gem::Version
96
+ version: 0.5.7
97
+ description: Turbo is a HTTP API tester, it's a curl wrapper
48
98
  email: juntao.qiu@gmail.com
49
99
  executables:
50
100
  - turbo
51
101
  extensions: []
52
102
  extra_rdoc_files: []
53
103
  files:
54
- - bin/before.sh,
55
104
  - bin/turbo
105
+ - lib/commander.rb
56
106
  - lib/config/browsers.json
57
107
  - lib/config/common.json
58
108
  - lib/config/turbo.conf
59
- - lib/hash_recursive_merge.rb
109
+ - lib/hash_recursive.rb
60
110
  - lib/templates/after.sh
61
111
  - lib/templates/before.sh
112
+ - lib/templates/command.erb
113
+ - lib/templates/output.erb
62
114
  - lib/templates/resource-get.json
63
115
  - lib/templates/resource.json
64
116
  - lib/templates/workflow.json
65
117
  - lib/turbo.rb
118
+ - lib/value_object.rb
66
119
  homepage: https://github.com/abruzzi/turbo
67
120
  licenses:
68
121
  - MIT
122
+ metadata: {}
69
123
  post_install_message:
70
124
  rdoc_options: []
71
125
  require_paths:
72
126
  - lib
73
127
  required_ruby_version: !ruby/object:Gem::Requirement
74
- none: false
75
128
  requirements:
76
129
  - - ! '>='
77
130
  - !ruby/object:Gem::Version
78
131
  version: '0'
79
132
  required_rubygems_version: !ruby/object:Gem::Requirement
80
- none: false
81
133
  requirements:
82
134
  - - ! '>='
83
135
  - !ruby/object:Gem::Version
84
136
  version: '0'
85
137
  requirements: []
86
138
  rubyforge_project:
87
- rubygems_version: 1.8.28
139
+ rubygems_version: 2.2.2
88
140
  signing_key:
89
- specification_version: 3
90
- summary: turbo is a curl wrapper for make test based on HTTP more easier
141
+ specification_version: 4
142
+ summary: Turbo is a HTTP API tester
91
143
  test_files: []
data/bin/before.sh, DELETED
File without changes
@@ -1,74 +0,0 @@
1
- #
2
- # = Hash Recursive Merge
3
- #
4
- # Merges a Ruby Hash recursively, Also known as deep merge.
5
- # Recursive version of Hash#merge and Hash#merge!.
6
- #
7
- # Category:: Ruby
8
- # Package:: Hash
9
- # Author:: Simone Carletti <weppos@weppos.net>
10
- # Copyright:: 2007-2008 The Authors
11
- # License:: MIT License
12
- # Link:: http://www.simonecarletti.com/
13
- # Source:: http://gist.github.com/gists/6391/
14
- #
15
- module HashRecursiveMerge
16
-
17
- #
18
- # Recursive version of Hash#merge!
19
- #
20
- # Adds the contents of +other_hash+ to +hsh+,
21
- # merging entries in +hsh+ with duplicate keys with those from +other_hash+.
22
- #
23
- # Compared with Hash#merge!, this method supports nested hashes.
24
- # When both +hsh+ and +other_hash+ contains an entry with the same key,
25
- # it merges and returns the values from both arrays.
26
- #
27
- # h1 = {"a" => 100, "b" => 200, "c" => {"c1" => 12, "c2" => 14}}
28
- # h2 = {"b" => 254, "c" => 300, "c" => {"c1" => 16, "c3" => 94}}
29
- # h1.rmerge!(h2) #=> {"a" => 100, "b" => 254, "c" => {"c1" => 16, "c2" => 14, "c3" => 94}}
30
- #
31
- # Simply using Hash#merge! would return
32
- #
33
- # h1.merge!(h2) #=> {"a" => 100, "b" = >254, "c" => {"c1" => 16, "c3" => 94}}
34
- #
35
- def rmerge!(other_hash)
36
- merge!(other_hash) do |key, oldval, newval|
37
- oldval.class == self.class ? oldval.rmerge!(newval) : newval
38
- end
39
- end
40
-
41
- #
42
- # Recursive version of Hash#merge
43
- #
44
- # Compared with Hash#merge!, this method supports nested hashes.
45
- # When both +hsh+ and +other_hash+ contains an entry with the same key,
46
- # it merges and returns the values from both arrays.
47
- #
48
- # Compared with Hash#merge, this method provides a different approch
49
- # for merging nasted hashes.
50
- # If the value of a given key is an Hash and both +other_hash+ abd +hsh
51
- # includes the same key, the value is merged instead replaced with
52
- # +other_hash+ value.
53
- #
54
- # h1 = {"a" => 100, "b" => 200, "c" => {"c1" => 12, "c2" => 14}}
55
- # h2 = {"b" => 254, "c" => 300, "c" => {"c1" => 16, "c3" => 94}}
56
- # h1.rmerge(h2) #=> {"a" => 100, "b" => 254, "c" => {"c1" => 16, "c2" => 14, "c3" => 94}}
57
- #
58
- # Simply using Hash#merge would return
59
- #
60
- # h1.merge(h2) #=> {"a" => 100, "b" = >254, "c" => {"c1" => 16, "c3" => 94}}
61
- #
62
- def rmerge(other_hash)
63
- r = {}
64
- merge(other_hash) do |key, oldval, newval|
65
- r[key] = oldval.class == self.class ? oldval.rmerge(newval) : newval
66
- end
67
- end
68
-
69
- end
70
-
71
-
72
- class Hash
73
- include HashRecursiveMerge
74
- end