Skip to content

Commit

Permalink
Add negative functional tests
Browse files Browse the repository at this point in the history
  • Loading branch information
dominickp committed Feb 11, 2024
1 parent cef3f2a commit 8ec01c9
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 6 deletions.
35 changes: 35 additions & 0 deletions docker/mock-4channel/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,41 @@ const port = 80;

const jsonFilePath = "/app/json";

// Helper function to check for comma seperated values in the x-forwarded-for header
// The x-forward-for might have a value like "4c-mock-delay=1,4c-mock-status-code=500"
// Would return the value of 1 if called for "4c-mock-delay" and 500 if called for "4c-mock-status-code"
function getXFFSignal(req, target) {
const xff = req.get("x-forwarded-for");
if (!xff) {
return null;
}
const signals = xff.split(",");
for (const signal of signals) {
const [key, value] = signal.split("=");
if (key === target) {
return value;
}
}
return null;
}

/** Middleware to check for generic signals */
app.use((req, res, next) => {
const delay = getXFFSignal(req, "4c-mock-delay");
const statusCode = getXFFSignal(req, "4c-mock-status-code");
if (delay) {
console.log(`Delaying response by ${delay} seconds`);
setTimeout(() => {
next();
}, delay * 1000);
} else if (statusCode) {
console.log(`Returning mock status code ${statusCode}`);
return res.sendStatus(statusCode);
} else {
next();
}
});

app.get("/", (req, res) => {
res.send("Welcome to mock-4channel.");
});
Expand Down
9 changes: 7 additions & 2 deletions go/src/client/chan_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"os"
"time"

"github.com/go-resty/resty/v2"
)
Expand Down Expand Up @@ -32,7 +33,8 @@ func init() {
host = getEnvString("CHAN_HOST", defaultChanHost)
restyClient = resty.New().
SetJSONMarshaler(json.Marshal).
SetJSONUnmarshaler(json.Unmarshal)
SetJSONUnmarshaler(json.Unmarshal).
SetTimeout(time.Duration(5) * time.Second) // Set timeout to 5 seconds
}

// GetCatalog retrieves the catalog of a supported SFW board.
Expand All @@ -54,13 +56,16 @@ func GetCatalog(board string, headers map[string]string) ([]CatalogPage, error)

// Call the 4channel API to get the catalog
catalogResponse := []CatalogPage{}
_, err := restyClient.R().
response, err := restyClient.R().
SetHeaders(headers).
SetResult(&catalogResponse).
Get(host + "/" + board + "/catalog.json")
if err != nil {
return nil, err
}
if response.IsError() {
return nil, errors.New(fmt.Sprintf("Error: %s", response.String()))
}

return catalogResponse, nil
}
6 changes: 4 additions & 2 deletions go/src/handler/catalog.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,11 @@ func HandleCatalog(c *gin.Context) {
}

// Forward along the x-forwarded-for header so the 4channel API knows the original IP of the user
headers := map[string]string{
"x-forwarded-for": c.ClientIP(),
xff := c.GetHeader("x-forwarded-for")
if xff == "" {
xff = c.ClientIP()
}
headers := map[string]string{"x-forwarded-for": xff}

catalog, err := client.GetCatalog(name, headers)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion javascript/src/chan_client.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class ChanClient {
const url = `${this.host}/${board}/catalog.json`;
const response = await fetch(url, {
method: "GET",
timeout: REQUEST_TIMEOUT,
signal: AbortSignal.timeout(REQUEST_TIMEOUT * 1000),
headers: headers,
});
if (!response.ok) {
Expand Down
2 changes: 1 addition & 1 deletion tests/functional/mock/config.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import os

REQUEST_TIMEOUT = 5
REQUEST_TIMEOUT = 15

GLUE_IMPLEMENTATIONS_CSV = os.environ.get("GLUE_IMPLEMENTATIONS_CSV")
if not GLUE_IMPLEMENTATIONS_CSV:
Expand Down
22 changes: 22 additions & 0 deletions tests/functional/mock/test_get_threads.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,25 @@ def test_get_threads_curl_page_4(host):
assert response.status_code == 400
assert response.headers["Content-Type"] == "text/plain; charset=utf-8"
assert response.text == f"Board {board} is not a supported SFW board."

@pytest.mark.parametrize("host", GLUE_IMPLEMENTATIONS)
def test_get_threads_negative_404(host):
"""
Signal to the 4channel mock to return a 404 on the get catalog fanout.
"""
url = f"{host}/po/1"
headers = {"x-forwarded-for": "4c-mock-status-code=404", "User-Agent": "curl/7.79.1"}
response = requests.get(url, headers=headers, timeout=REQUEST_TIMEOUT)
assert response.status_code == 500
assert response.headers["Content-Type"] == "text/plain; charset=utf-8"

@pytest.mark.parametrize("host", GLUE_IMPLEMENTATIONS)
def test_get_threads_negative_timeout(host):
"""
Signal to the 4channel mock to delay it's response by 10 seconds, which should cause a timeout (after 5 seconds).
"""
url = f"{host}/po/1"
headers = {"x-forwarded-for": "4c-mock-delay=10", "User-Agent": "curl/7.79.1"}
response = requests.get(url, headers=headers, timeout=REQUEST_TIMEOUT)
assert response.status_code == 500
assert response.headers["Content-Type"] == "text/plain; charset=utf-8"

0 comments on commit 8ec01c9

Please sign in to comment.