Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ jobs:
with:
php-version: ${{ matrix.php-versions }}
ini-file: development
ini-values: output_buffering=Off
extensions: none opcache
extensions: opcache
coverage: none
env:
phpts: ts
Expand Down
4 changes: 2 additions & 2 deletions Dockerfile.dev
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,10 @@ RUN git clone --branch=PHP-8.2 https://github.com/php/php-src.git && \
make -j$(nproc) && \
make install && \
ldconfig && \
cp php.ini-development /usr/local/lib/php.ini && \
echo "zend_extension=opcache.so\nopcache.enable=1" >> /usr/local/lib/php.ini &&\
php --version

RUN echo "zend_extension=opcache.so\nopcache.enable=1" > /usr/local/lib/php.ini

WORKDIR /go/src/app

COPY . .
Expand Down
128 changes: 25 additions & 103 deletions frankenphp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import (
"strings"
"sync"
"testing"
"time"

"github.com/dunglas/frankenphp"
"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -404,115 +403,38 @@ func testLog(t *testing.T, opts *testOptions) {
w := httptest.NewRecorder()
handler(w, req)

var found bool
searched := fmt.Sprintf("request %d", i)
for _, entry := range logs.All() {
if entry.Message == searched {
found = true
break
}
}

assert.True(t, found)
}, opts)
}

func TestConnectionAbortNormal_module(t *testing.T) { testConnectionAbortNormal(t, &testOptions{}) }
func TestConnectionAbortNormal_worker(t *testing.T) {
testConnectionAbortNormal(t, &testOptions{workerScript: "connectionStatusLog.php"})
}
func testConnectionAbortNormal(t *testing.T, opts *testOptions) {
logger, logs := observer.New(zap.InfoLevel)
opts.logger = zap.New(logger)

runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) {
req := httptest.NewRequest("GET", fmt.Sprintf("http://example.com/connectionStatusLog.php?i=%d", i), nil)
w := httptest.NewRecorder()

ctx, cancel := context.WithCancel(req.Context())
req = req.WithContext(ctx)
cancel()
handler(w, req)

// todo: remove conditions on wall clock to avoid race conditions/flakiness
time.Sleep(1000 * time.Microsecond)
var found bool
searched := fmt.Sprintf("request %d: 1", i)
for _, entry := range logs.All() {
if entry.Message == searched {
found = true
break
}
}

assert.True(t, found)
}, opts)
}

func TestConnectionAbortFlush_module(t *testing.T) { testConnectionAbortFlush(t, &testOptions{}) }
func TestConnectionAbortFlush_worker(t *testing.T) {
testConnectionAbortFlush(t, &testOptions{workerScript: "connectionStatusLog.php"})
}
func testConnectionAbortFlush(t *testing.T, opts *testOptions) {
logger, logs := observer.New(zap.InfoLevel)
opts.logger = zap.New(logger)

runTest(t, func(handler func(w http.ResponseWriter, response *http.Request), _ *httptest.Server, i int) {
req := httptest.NewRequest("GET", fmt.Sprintf("http://example.com/connectionStatusLog.php?i=%d&flush", i), nil)
w := httptest.NewRecorder()

ctx, cancel := context.WithCancel(req.Context())
req = req.WithContext(ctx)
cancel()
handler(w, req)

// todo: remove conditions on wall clock to avoid race conditions/flakiness
time.Sleep(1000 * time.Microsecond)
var found bool
searched := fmt.Sprintf("request %d: 1", i)
for _, entry := range logs.All() {
if entry.Message == searched {
found = true
break
}
for logs.FilterMessage(fmt.Sprintf("request %d", i)).Len() <= 0 {
}

assert.True(t, found)
}, opts)
}

func TestConnectionAbortFinish_module(t *testing.T) { testConnectionAbortFinish(t, &testOptions{}) }
func TestConnectionAbortFinish_worker(t *testing.T) {
testConnectionAbortFinish(t, &testOptions{workerScript: "connectionStatusLog.php"})
func TestConnectionAbort_module(t *testing.T) { testConnectionAbort(t, &testOptions{}) }
func TestConnectionAbort_worker(t *testing.T) {
testConnectionAbort(t, &testOptions{workerScript: "connectionStatusLog.php"})
}
func testConnectionAbortFinish(t *testing.T, opts *testOptions) {
t.Skip("Flaky")

logger, logs := observer.New(zap.InfoLevel)
opts.logger = zap.New(logger)
func testConnectionAbort(t *testing.T, opts *testOptions) {
testFinish := func(finish string) {
t.Run(fmt.Sprintf("finish=%s", finish), func(t *testing.T) {
logger, logs := observer.New(zap.InfoLevel)
opts.logger = zap.New(logger)

runTest(t, func(handler func(w http.ResponseWriter, response *http.Request), _ *httptest.Server, i int) {
req := httptest.NewRequest("GET", fmt.Sprintf("http://example.com/connectionStatusLog.php?i=%d&finish", i), nil)
w := httptest.NewRecorder()
runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) {
req := httptest.NewRequest("GET", fmt.Sprintf("http://example.com/connectionStatusLog.php?i=%d&finish=%s", i, finish), nil)
w := httptest.NewRecorder()

ctx, cancel := context.WithCancel(req.Context())
req = req.WithContext(ctx)
cancel()
handler(w, req)
ctx, cancel := context.WithCancel(req.Context())
req = req.WithContext(ctx)
cancel()
handler(w, req)

// todo: remove conditions on wall clock to avoid race conditions/flakiness
time.Sleep(1000 * time.Microsecond)
var found bool
searched := fmt.Sprintf("request %d: 0", i)
for _, entry := range logs.All() {
if entry.Message == searched {
found = true
break
}
}
for logs.FilterMessage(fmt.Sprintf("request %d: 1", i)).Len() <= 0 {
}
}, opts)
})
}

assert.True(t, found)
}, opts)
testFinish("0")
testFinish("1")
}

func TestException_module(t *testing.T) { testException(t, &testOptions{}) }
Expand Down Expand Up @@ -605,11 +527,11 @@ func TestTimeout_module(t *testing.T) {
}

func TestTimeout_worker(t *testing.T) {
t.Skip("Race condition")

testTimeout(t, &testOptions{workerScript: "timeout.php"})
}
func testTimeout(t *testing.T, opts *testOptions) {
t.Skip("config-dependant")

config := frankenphp.Config()
if !config.ZendMaxExecutionTimers {
t.Skip("Zend Timer is not enabled")
Expand Down
7 changes: 3 additions & 4 deletions testdata/connectionStatusLog.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@
require_once __DIR__.'/_executor.php';

return function () {
if(isset($_GET['finish'])) {
if($_GET['finish'] ?? false) {
frankenphp_finish_request();
}

echo 'hi';
if(isset($_GET['flush'])) {
flush();
}
flush();
$status = (string) connection_status();
error_log("request {$_GET['i']}: " . $status);
};
2 changes: 1 addition & 1 deletion testdata/die.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@
echo 'Hello, world';
});

die('Hello');
die();
} while ($ok);
6 changes: 6 additions & 0 deletions testdata/flush.php
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
<?php


require_once __DIR__.'/_executor.php';

return function () {
if (ini_get("output_buffering") !== "0") {
// Disable output buffering if not already done
while (@ob_end_flush());
}

echo 'He';

flush();
Expand Down