cuke4php 0.9.6.c → 0.9.8

Sign up to get free protection for your applications and to get access to all the features.
data/HISTORY CHANGED
@@ -18,3 +18,6 @@
18
18
  * utilizes cucumber 0.10.2's ability to use erb templates in .wire files to listen to a specific port
19
19
  * release 0.9.3
20
20
  * modify cuke4php runner script to dynamically pick an unused port
21
+
22
+ 2011-08-30 -- 0.9.8
23
+ * add support for a forking socket listener
data/Rakefile CHANGED
@@ -27,6 +27,9 @@ begin
27
27
  Install PHPUnit:
28
28
  pear install phpunit/PHPUnit
29
29
 
30
+ Optional: Use PEAR/Net_Server for a remote forking server implementation
31
+ (requires PHP with pcntl extensions)
32
+
30
33
  ********************************************************************************
31
34
  eos
32
35
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.9.6.c
1
+ 0.9.8
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env ruby
2
+ exec File.dirname(__FILE__) + "/../php_bin/cuke4php_forking_server.php #{ARGV.join(' ')}"
data/cuke4php.gemspec CHANGED
@@ -5,14 +5,14 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{cuke4php}
8
- s.version = "0.9.6.c"
8
+ s.version = "0.9.8"
9
9
 
10
- s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["Kevin Olbrich", "Alessandro Dal Grande"]
12
- s.date = %q{2011-05-07}
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = [%q{Kevin Olbrich}, %q{Alessandro Dal Grande}]
12
+ s.date = %q{2011-08-31}
13
13
  s.description = %q{Using this protocol it is possible to directly interact with PHP code at any level without the need for a web server. To accomplish this, when cucumber is running against a directory containing feature files and it cannot resolve a particular step definition, it will ask a known wire server (as defined in a .wire file) to interpret and run those steps.}
14
- s.email = ["kevin.olbrich+cuke4php@gmail.com", "aledalgrande@gmail.com"]
15
- s.executables = ["cuke4php_server", "cuke4php"]
14
+ s.email = [%q{kevin.olbrich+cuke4php@gmail.com}, %q{aledalgrande@gmail.com}]
15
+ s.executables = [%q{cuke4php_forking_server}, %q{cuke4php_server}, %q{cuke4php}]
16
16
  s.extra_rdoc_files = [
17
17
  "LICENSE",
18
18
  "README.md"
@@ -26,6 +26,7 @@ Gem::Specification.new do |s|
26
26
  "Rakefile",
27
27
  "VERSION",
28
28
  "bin/cuke4php",
29
+ "bin/cuke4php_forking_server",
29
30
  "bin/cuke4php_server",
30
31
  "cucumber.yml",
31
32
  "cuke4php.gemspec",
@@ -40,11 +41,12 @@ Gem::Specification.new do |s|
40
41
  "lib/CucumberScenario.php",
41
42
  "lib/CucumberSteps.php",
42
43
  "lib/Cuke4Php.php",
44
+ "lib/Cuke4PhpForkingServer.php",
45
+ "php_bin/cuke4php_forking_server.php",
43
46
  "php_bin/cuke4php_server.php",
44
47
  "tests/lib/CucumberScenarioTest.php",
45
48
  "tests/lib/Cuke4PhpTest.php"
46
49
  ]
47
- s.has_rdoc = false
48
50
  s.homepage = %q{http://github.com/olbrich/cuke4php}
49
51
  s.post_install_message = %q{********************************************************************************
50
52
 
@@ -58,15 +60,17 @@ Gem::Specification.new do |s|
58
60
  Install PHPUnit:
59
61
  pear install phpunit/PHPUnit
60
62
 
63
+ Optional: Use PEAR/Net_Server for a remote forking server implementation
64
+ (requires PHP with pcntl extensions)
65
+
61
66
  ********************************************************************************
62
67
  }
63
- s.require_paths = ["lib"]
64
- s.requirements = ["PHP 5.2+", "PHPUnit 3.0+"]
65
- s.rubygems_version = %q{1.3.7}
68
+ s.require_paths = [%q{lib}]
69
+ s.requirements = [%q{PHP 5.2+}, %q{PHPUnit 3.0+}]
70
+ s.rubygems_version = %q{1.8.5}
66
71
  s.summary = %q{Implementation of the Cucumber wire protocol for PHP projects}
67
72
 
68
73
  if s.respond_to? :specification_version then
69
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
70
74
  s.specification_version = 3
71
75
 
72
76
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
@@ -54,4 +54,7 @@ Scenario Outline: Error Handling
54
54
  @exception
55
55
  Scenario: Exception Handling
56
56
  When an "Exception" is thrown with message "generic exception"
57
- Then an "Exception" should be caught
57
+ Then an "Exception" should be caught
58
+
59
+ Scenario: nested capture groups work fine
60
+ Given the losing code "one" has the prize "two"
@@ -1,4 +1,2 @@
1
1
  host: localhost
2
2
  port: <%= ENV['CUKE4PHP_PORT'] || 16816 %>
3
- invoke:
4
- timeout: 0.1
@@ -231,6 +231,13 @@ class WireSteps extends CucumberSteps {
231
231
  self::assertInternalType($sTypeName, $this->$sKey);
232
232
  }
233
233
 
234
+ /**
235
+ * Given /^the(?: losing)? code "([^"]*)"(?: has the prize "([^"]*)")?$/
236
+ **/
237
+ public function stepTheLosingCodeParameterHasThePrizeParameter($sCode, $sPrize) {
238
+ $this->$sCode = $sPrize;
239
+ }
240
+
234
241
  }
235
242
 
236
243
  ?>
@@ -66,6 +66,7 @@ class CucumberScenario {
66
66
  if (array_key_exists('tags', $aBeforeHook)) {
67
67
  if (count($aBeforeHook['tags']) == 0 || count(array_intersect($aTags, $aBeforeHook['tags'])) > 0) {
68
68
  $oStep = CucumberSteps::getInstance($aBeforeHook['class'], $this->aGlobals);
69
+ syslog(LOG_DEBUG,"Invoking Before Hook \"{$aBeforeHook['method']}\"");
69
70
  $oResult = $oStep->invoke($aBeforeHook['method']);
70
71
  if ($oResult === false) {
71
72
  return array('failure');
@@ -89,6 +90,7 @@ class CucumberScenario {
89
90
  if (array_key_exists('tags', $aAfterHook)) {
90
91
  if (count($aAfterHook['tags']) == 0 || count(array_intersect($aTags, $aAfterHook['tags'])) > 0) {
91
92
  $oStep = CucumberSteps::getInstance($aAfterHook['class'], $this->aGlobals);
93
+ syslog(LOG_DEBUG,"Invoking After Hook \"{$aAfterHook['method']}\"");
92
94
  $oResult = $oStep->invoke($aAfterHook['method']);
93
95
  if ($oResult === false) {
94
96
  return array('failure');
@@ -132,14 +134,19 @@ class CucumberScenario {
132
134
 
133
135
  }
134
136
  try {
137
+ syslog(LOG_DEBUG,"Invoking Step \"{$aStep['method']}\"");
135
138
  call_user_func_array(array($oStep, $aStep['method']),$aArgs);
136
139
  } catch (PHPUnit_Framework_IncompleteTestError $e) {
140
+ syslog(LOG_DEBUG,"Step Pending");
137
141
  return array('pending',$e->getMessage());
138
142
  } catch (PHPUnit_Framework_SkippedTestError $e) {
143
+ syslog(LOG_DEBUG,"Step Pending");
139
144
  return array('pending',$e->getMessage());
140
145
  } catch (PHPUnit_Framework_ExpectationFailedException $e) {
146
+ syslog(LOG_DEBUG,"Step Failed due to unmet expectation: " . $e->getMessage());
141
147
  return array('fail', array('message' => $e->getMessage()));
142
148
  } catch (Exception $e) {
149
+ syslog(LOG_DEBUG,"Step failed due to ". get_class($e) ." exception :" . $e->getMessage());
143
150
  return array('fail', array('message' => $e->getMessage() . " " . $e->getFile() . ":" . $e->getLine(), 'exception' => get_class($e), 'backtrace' => $e->getTraceAsString()));
144
151
  }
145
152
  return array('success');
data/lib/Cuke4Php.php CHANGED
@@ -26,6 +26,7 @@ class Cuke4Php {
26
26
  );
27
27
 
28
28
  function __construct($_sFeaturePath, $_iPort = 16816) {
29
+ openlog("cuke4php", LOG_PID, LOG_DAEMON);
29
30
  if (is_file($_sFeaturePath)) {
30
31
  $_sFeaturePath = dirname($_sFeaturePath);
31
32
  }
@@ -119,21 +120,40 @@ class Cuke4Php {
119
120
  }
120
121
 
121
122
  function run() {
122
- print "Cuke4Php listening on port $this->iPort\n";
123
+ syslog(LOG_INFO,"Cuke4Php listening on port $this->iPort\n");
123
124
  $this->oSocket = socket_create_listen($this->iPort);
124
125
  $this->bRun = true;
125
126
  while ($this->bRun && ($connection = socket_accept($this->oSocket))) {
126
127
  socket_getpeername($connection, $raddr, $rport);
127
- while ($this->bRun && ($input = socket_read($connection, 1024 * 4))) {
128
- $data = trim($input);
129
- if ($data !== "") {
130
- $output = json_encode($this->process($data)) . "\n";
131
- if ($this->bRun) {
132
- socket_write($connection, $output);
128
+ syslog(LOG_INFO,"Connection from $raddr");
129
+ try {
130
+ while ($this->bRun && ($input = socket_read($connection, 4096, PHP_NORMAL_READ))) {
131
+ $data = trim($input);
132
+ if ($data !== "") {
133
+ $output = json_encode($this->process($data)) . "\n";
134
+ if ($this->bRun) {
135
+ socket_write($connection, $output);
136
+ }
133
137
  }
138
+ }
139
+ } catch (Exception $e) {
140
+ switch (socket_last_error($connection)) {
141
+ case 54:
142
+ // connection closed by peer
143
+ case 104:
144
+ // unable to read from socket
145
+ // these errors just mean we are done and the connection should be closed.
146
+ // it does not mean we should stop listening for new connections.
147
+ break;
148
+
149
+ default:
150
+ syslog(LOG_ERR,$e->getMessage());
151
+ throw $e;
152
+ break;
134
153
  }
135
154
  }
136
155
  socket_close($connection);
156
+ syslog(LOG_INFO,"Connection closed");
137
157
  sleep(1);
138
158
  }
139
159
  }
@@ -183,6 +203,7 @@ class Cuke4Php {
183
203
  * run any before hooks for a scenario
184
204
  */
185
205
  function beginScenario($aTags) {
206
+ syslog(LOG_DEBUG,"Begin Scenario: Tags: " . implode(", ", $aTags));
186
207
  $this->setScenario(CucumberScenario::getInstance($this->aWorld));
187
208
  return $this->oScenario->invokeBeforeHooks($aTags);
188
209
  }
@@ -216,6 +237,7 @@ class Cuke4Php {
216
237
  */
217
238
  function endScenario($aTags) {
218
239
  $oResult = $this->oScenario->invokeAfterHooks($aTags);
240
+ syslog(LOG_DEBUG,"End Scenario");
219
241
  $this->oScenario = null;
220
242
  return $oResult;
221
243
  }
@@ -0,0 +1,34 @@
1
+ <?php
2
+
3
+ /**
4
+ * This class allows multiple concurrent connections to the same Cuke4php port. Each connection forks a process that
5
+ * loads the same feature files and then runs the step definitions. This is useful for cases where the Cuke4php server
6
+ * is deployed to a remote machine and multiple automation scripts are simultaneously connecting to the server.
7
+ *
8
+ * Uses the PEAR Net_Server package
9
+ **/
10
+
11
+ require_once "Cuke4Php.php";
12
+ require_once "Net/Server.php";
13
+ require_once "Net/Server/Handler.php";
14
+
15
+ class Cuke4PhpForkingServer extends Net_Server_Handler
16
+ {
17
+ private $cuke4php;
18
+
19
+ function __construct($_sFeaturePath, $_iPort) {
20
+ $this->cuke4php = new Cuke4Php($_sFeaturePath, $_iPort);
21
+ }
22
+
23
+ function onReceiveData($iClientId = 0, $data = "") {
24
+ $output = json_encode($this->cuke4php->process($data)) . "\n";
25
+ $this->_server->sendData($iClientId, $output);
26
+ }
27
+
28
+ function onClose($iClientId) {
29
+ // Do nothing
30
+ }
31
+ }
32
+
33
+
34
+ ?>
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env php
2
+ <?php
3
+ /**
4
+ * main entry point for starting a Cuke4Php wire server
5
+ * @package Cuke4Php
6
+ */
7
+
8
+ /**
9
+ * load the Cuke4PhpForkingServer server
10
+ */
11
+ require_once dirname(__FILE__) . "/../lib/Cuke4PhpForkingServer.php";
12
+
13
+ $aOptions = getopt("p:");
14
+ if (array_key_exists('p',$aOptions)) {
15
+ $iPort = $aOptions['p'];
16
+ } else {
17
+ $iPort = 16816;
18
+ }
19
+
20
+ $oServer = &Net_Server::create('fork','0.0.0.0', $iPort);
21
+ $oServerHandler = &new Cuke4PhpForkingServer(realpath($argv[$argc-1]), $iPort);
22
+ $oServer->setCallbackObject($oServerHandler);
23
+ $oServer->start();
24
+ ?>
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cuke4php
3
3
  version: !ruby/object:Gem::Version
4
- hash: 120
5
- prerelease: true
4
+ hash: 43
5
+ prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 9
9
- - 6
10
- - c
11
- version: 0.9.6.c
9
+ - 8
10
+ version: 0.9.8
12
11
  platform: ruby
13
12
  authors:
14
13
  - Kevin Olbrich
@@ -17,11 +16,10 @@ autorequire:
17
16
  bindir: bin
18
17
  cert_chain: []
19
18
 
20
- date: 2011-05-07 00:00:00 -04:00
21
- default_executable:
19
+ date: 2011-08-31 00:00:00 Z
22
20
  dependencies:
23
21
  - !ruby/object:Gem::Dependency
24
- requirement: &id001 !ruby/object:Gem::Requirement
22
+ version_requirements: &id001 !ruby/object:Gem::Requirement
25
23
  none: false
26
24
  requirements:
27
25
  - - ">="
@@ -33,11 +31,11 @@ dependencies:
33
31
  - 2
34
32
  version: 0.10.2
35
33
  type: :runtime
36
- name: cucumber
34
+ requirement: *id001
37
35
  prerelease: false
38
- version_requirements: *id001
36
+ name: cucumber
39
37
  - !ruby/object:Gem::Dependency
40
- requirement: &id002 !ruby/object:Gem::Requirement
38
+ version_requirements: &id002 !ruby/object:Gem::Requirement
41
39
  none: false
42
40
  requirements:
43
41
  - - ~>
@@ -48,11 +46,11 @@ dependencies:
48
46
  - 0
49
47
  version: "1.0"
50
48
  type: :development
51
- name: bundler
49
+ requirement: *id002
52
50
  prerelease: false
53
- version_requirements: *id002
51
+ name: bundler
54
52
  - !ruby/object:Gem::Dependency
55
- requirement: &id003 !ruby/object:Gem::Requirement
53
+ version_requirements: &id003 !ruby/object:Gem::Requirement
56
54
  none: false
57
55
  requirements:
58
56
  - - ">="
@@ -62,14 +60,15 @@ dependencies:
62
60
  - 0
63
61
  version: "0"
64
62
  type: :development
65
- name: jeweler
63
+ requirement: *id003
66
64
  prerelease: false
67
- version_requirements: *id003
65
+ name: jeweler
68
66
  description: Using this protocol it is possible to directly interact with PHP code at any level without the need for a web server. To accomplish this, when cucumber is running against a directory containing feature files and it cannot resolve a particular step definition, it will ask a known wire server (as defined in a .wire file) to interpret and run those steps.
69
67
  email:
70
68
  - kevin.olbrich+cuke4php@gmail.com
71
69
  - aledalgrande@gmail.com
72
70
  executables:
71
+ - cuke4php_forking_server
73
72
  - cuke4php_server
74
73
  - cuke4php
75
74
  extensions: []
@@ -86,6 +85,7 @@ files:
86
85
  - Rakefile
87
86
  - VERSION
88
87
  - bin/cuke4php
88
+ - bin/cuke4php_forking_server
89
89
  - bin/cuke4php_server
90
90
  - cucumber.yml
91
91
  - cuke4php.gemspec
@@ -100,10 +100,11 @@ files:
100
100
  - lib/CucumberScenario.php
101
101
  - lib/CucumberSteps.php
102
102
  - lib/Cuke4Php.php
103
+ - lib/Cuke4PhpForkingServer.php
104
+ - php_bin/cuke4php_forking_server.php
103
105
  - php_bin/cuke4php_server.php
104
106
  - tests/lib/CucumberScenarioTest.php
105
107
  - tests/lib/Cuke4PhpTest.php
106
- has_rdoc: false
107
108
  homepage: http://github.com/olbrich/cuke4php
108
109
  licenses: []
109
110
 
@@ -120,6 +121,9 @@ post_install_message: |
120
121
  Install PHPUnit:
121
122
  pear install phpunit/PHPUnit
122
123
 
124
+ Optional: Use PEAR/Net_Server for a remote forking server implementation
125
+ (requires PHP with pcntl extensions)
126
+
123
127
  ********************************************************************************
124
128
 
125
129
  rdoc_options: []
@@ -138,19 +142,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
138
142
  required_rubygems_version: !ruby/object:Gem::Requirement
139
143
  none: false
140
144
  requirements:
141
- - - ">"
145
+ - - ">="
142
146
  - !ruby/object:Gem::Version
143
- hash: 25
147
+ hash: 3
144
148
  segments:
145
- - 1
146
- - 3
147
- - 1
148
- version: 1.3.1
149
+ - 0
150
+ version: "0"
149
151
  requirements:
150
152
  - PHP 5.2+
151
153
  - PHPUnit 3.0+
152
154
  rubyforge_project:
153
- rubygems_version: 1.3.7
155
+ rubygems_version: 1.8.5
154
156
  signing_key:
155
157
  specification_version: 3
156
158
  summary: Implementation of the Cucumber wire protocol for PHP projects