Skip to content

Commit

Permalink
Add initial phpt support
Browse files Browse the repository at this point in the history
This splits a phpt file into some of its sections and runs the --FILE--
section as if were a script. This also changes normal behavior to use a
mmapped file instead of opening for each request. This currently does
not check the --SKIPIF-- ection nor compare the result.
  • Loading branch information
johannes committed Oct 4, 2014
1 parent df5134e commit 9a2f6b0
Show file tree
Hide file tree
Showing 6 changed files with 280 additions and 20 deletions.
2 changes: 1 addition & 1 deletion config.m4
Expand Up @@ -11,7 +11,7 @@ if test "$PHP_PCONN" != "no"; then
PHP_ADD_MAKEFILE_FRAGMENT($abs_srcdir/sapi/pconn/Makefile.frag)
SAPI_PCONN_PATH=sapi/pconn/php-pconn
PHP_SUBST(SAPI_PCONN_PATH)
PHP_SELECT_SAPI(pconn, program, main.c pconnect-module.c pconnect-sapi.c, "", '$(SAPI_PCONN_PATH)')
PHP_SELECT_SAPI(pconn, program, main.c pconnect-module.c pconnect-sapi.c pconnect-phptparser.c, "", '$(SAPI_PCONN_PATH)')
if test $PHP_VERSION_ID -ge 50400; then
BUILD_PCONN="\$(LIBTOOL) --mode=link \$(CC) -export-dynamic \$(CFLAGS_CLEAN) \$(EXTRA_CFLAGS) \$(EXTRA_LDFLAGS_PROGRAM) \$(LDFLAGS) \$(PHP_RPATHS) \$(PHP_GLOBAL_OBJS) \$(PHP_BINARY_OBJS) \$(PHP_PCONN_OBJS) \$(EXTRA_LIBS) \$(ZEND_EXTRA_LIBS) -o \$(SAPI_PCONN_PATH)"
else
Expand Down
100 changes: 91 additions & 9 deletions main.c
Expand Up @@ -18,17 +18,28 @@
#include <unistd.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include "pconnect.h"
#include "main/php_version.h"
#include "main/php_getopt.h"
#include "main/php_streams.h"
#include "pconnect-sapi.h"
#include "pconnect-phptparser.h"

#define MAX_THREADS 255

typedef struct {
int iterations;
char *main_script;
char *phpt_skipif_script_data;
char *filename;
char *mmapped;
size_t mmapped_len;
struct phpt phpt;
char *startup_script;
char *shutdown_script;
} req_data;
Expand All @@ -45,6 +56,7 @@ const opt_struct OPTIONS[] = {
{'p', 0, "progress"},
{'a', 1, "init-script"},
{'z', 1, "shutdown-script"},
{10, 0, "phpt"},
{'-', 0, NULL}
};

Expand All @@ -57,12 +69,17 @@ static void run_php(req_data *data TSRMLS_DC)
int i = data->iterations;

if (data->startup_script) {
pconn_do_request(data->startup_script, &user_data, &user_data_len TSRMLS_CC);
pconn_do_request_f(data->startup_script, &user_data, &user_data_len TSRMLS_CC);
}

while (i--) {
int retval;
retval = pconn_do_request(data->main_script, &user_data, &user_data_len TSRMLS_CC);

if (data->phpt.file.begin) {
retval = pconn_do_request_d(data->filename, data->phpt.file.begin, data->phpt.file.end - data->phpt.file.begin, &user_data, &user_data_len TSRMLS_CC);
} else {
retval = pconn_do_request_d(data->filename, data->mmapped, data->mmapped_len, &user_data, &user_data_len TSRMLS_CC);
}

if (retval == FAILURE) {
#ifdef FIX_ME
Expand All @@ -78,7 +95,7 @@ static void run_php(req_data *data TSRMLS_DC)
printf("\n");
}
if (data->shutdown_script) {
pconn_do_request(data->shutdown_script, &user_data, &user_data_len TSRMLS_CC);
pconn_do_request_f(data->shutdown_script, &user_data, &user_data_len TSRMLS_CC);
}
if (user_data) {
free(user_data);
Expand Down Expand Up @@ -141,7 +158,7 @@ static void usage(const char *name, const int status)
#ifdef ZTS
" [-t <threads>]"
#endif
" [-a <startup>] [-z <shutdown>] <script>\n"
" [-a <startup>] [-z <shutdown>] [--phpt] <script>\n"
" %s -v\n"
" %s -i\n\n"
" -v Print version information\n"
Expand All @@ -158,6 +175,7 @@ static void usage(const char *name, const int status)
")\n"
" -a <startup> Startup script, executed once on start\n"
" -z <shutdown> Shutdown script, executed once on end\n"
" --phpt Treat <script> as phpt\n"
" <script> Main script to be executed multiple times\n\n"
, name
, name
Expand Down Expand Up @@ -193,6 +211,60 @@ static void pconn_version()
);
}

static int process_phpt(req_data *data)
{
if (data->mmapped_len < 100) {
printf("Too small, can't be a test!\n");
return 1;
}
if (memcmp("--TEST--", data->mmapped, sizeof("--TEST--")-1)) {
printf("Not a phpt test file\n");
return 1;
}

parse_phpt(&data->phpt, data->mmapped, data->mmapped + data->mmapped_len);

return 0;
}

static int init_script_data(req_data *data, int is_phpt)
{
int fd;
struct stat ssb;

if (!(fd = open(data->filename, O_RDONLY))) {
printf("Failed opening file\n");
return 1;
}

if (fstat(fd, &ssb)) {
close(fd);
printf("Failed to stat the opened file");
return 1;
}

data->mmapped_len = ssb.st_size;
data->mmapped = mmap(NULL, data->mmapped_len, PROT_READ, MAP_PRIVATE, fd, 0);
close(fd);

if (!data->mmapped) {
printf("Error while mapping file content");
return 1;
}

if (is_phpt) {
if (process_phpt(data)) {
return 1;
}

printf("Running test: ");
fflush(stdout);
write(STDOUT_FILENO, data->phpt.test.begin, data->phpt.test.end - data->phpt.test.begin);
}

return 0;
}

int main(int argc, char *argv[])
{
#ifdef ZTS
Expand All @@ -201,7 +273,8 @@ int main(int argc, char *argv[])
int opt;
char *php_optarg = NULL;
int php_optind = 1;
req_data data = { 2, NULL, NULL, NULL };
req_data data = { 2, NULL, NULL, NULL, 0, {}, NULL, NULL };
int is_phpt = 0;

while ((opt = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2)) != -1) {
switch (opt) {
Expand Down Expand Up @@ -237,6 +310,9 @@ int main(int argc, char *argv[])
case 'p':
pconn_report_progress = 1;
break;
case 10:
is_phpt = 1;
break;
default:
usage(argv[0], 1); /* terminates */
case 'h':
Expand All @@ -248,15 +324,21 @@ int main(int argc, char *argv[])
usage(argv[0], 1); /* terminates */
}

data.main_script = argv[php_optind];

pconn_init_php();

data.filename = argv[php_optind];
if (init_script_data(&data, is_phpt)) {
return 1;
}

#ifdef ZTS
run_threads(&data, threads);
#else
run_php(&data);
#endif

pconn_shutdown_php();
munmap(data.mmapped, data.mmapped_len);
return 0;
}

Expand Down
102 changes: 102 additions & 0 deletions pconnect-phptparser.c
@@ -0,0 +1,102 @@
/*
+----------------------------------------------------------------------+
| Copyright (c) 2009-2014, Johannes Schlüter <johannes@schlueters.de> |
| All rights reserved. |
+----------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions which are |
| bundled with this package in the file LICENSE. |
| This product includes PHP software, freely available from |
|<http://www.php.net/software/> |
+----------------------------------------------------------------------+
*/

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#include "pconnect-phptparser.h"

static void switch_section(struct phpt *phpt, phpt_section **section, char *begin, char *end)
{
size_t len = end - begin + 1;

if (*section) {
(*section)->end = begin - 2; /* -2 for "--" */
}

#define COMPARE_SECTION(name) len == sizeof(name)-1 && !memcmp(name, begin, len)

if (COMPARE_SECTION("TEST")) {
*section = &phpt->test;
} else if (COMPARE_SECTION("INI")) {
*section = &phpt->ini;
} else if (COMPARE_SECTION("FILE")) {
*section = &phpt->file;
} else if (COMPARE_SECTION("XFAIL")) {
*section = &phpt->xfail;
} else if (COMPARE_SECTION("EXPECT")) {
*section = &phpt->expect;
phpt->type = EXPECT;
} else if (COMPARE_SECTION("EXPECTF")) {
*section = &phpt->expect;
phpt->type = EXPECTF;
} else if (COMPARE_SECTION("EXPECTREGEX")) {
*section = &phpt->expect;
phpt->type = EXPECTREGEX;
} else {
/* Error */
*section = NULL;
printf("Invalid section '%12s' (%li)\n", begin, len);
return;
}

(*section)->begin = begin + len + 3;
}

void parse_phpt(struct phpt *phpt, char *buffer, char *end)
{
int state = 0; /* 0 = beginning of line, 1 = in section title, 2 = some text */
char *section_name = NULL;
phpt_section *current_section = NULL;
memset(phpt, 0, sizeof(struct phpt));

for (; buffer < end; ++buffer) {
switch (state) {
case 0:
if (*buffer == '-' && *(buffer+1) == '-') {
buffer += 2;
state = 1;
section_name = buffer;
} else if (*buffer == '\r' || *buffer == '\n') {
/* ignored - we'Re still at the beginning of a line */
} else {
state = 2;
}
break;
case 1:
if (*buffer == '-' && *(buffer+1) == '-') {
switch_section(phpt, &current_section, section_name, buffer-1);
buffer += 3; /* 3 for "--\n", if the test uses \r\n test script will start with \n which is ok */
state = 0;
}
break;
case 2:
if (*buffer == '\r' || *buffer == '\n') {
state = 0;
}
}
}
if (current_section) {
current_section->end = end;
}
}

/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: ft=c noet sw=4 ts=4 fdm=marker
* vim<600: ft=c noet sw=4 ts=4
*/
47 changes: 47 additions & 0 deletions pconnect-phptparser.h
@@ -0,0 +1,47 @@
/*
+----------------------------------------------------------------------+
| Copyright (c) 2009-2014, Johannes Schlüter <johannes@schlueters.de> |
| All rights reserved. |
+----------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions which are |
| bundled with this package in the file LICENSE. |
| This product includes PHP software, freely available from |
|<http://www.php.net/software/> |
+----------------------------------------------------------------------+
*/

#ifndef PCONNECT_PHPTPARSER_H
#define PCONNECT_PHPTPARSER_H

typedef struct {
char *begin;
char *end;
} phpt_section;

enum expect_type {
EXPECT,
EXPECTF,
EXPECTREGEX
};

struct phpt {
phpt_section test;
phpt_section ini;
phpt_section file;
phpt_section xfail;
enum expect_type type;
phpt_section expect;
};

void parse_phpt(struct phpt *phpt, char *buffer, char *end);

#endif
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: ft=c noet sw=4 ts=4 fdm=marker
* vim<600: ft=c noet sw=4 ts=4
*/

0 comments on commit 9a2f6b0

Please sign in to comment.