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
68 changes: 56 additions & 12 deletions jest.setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ const resetMockServer = async () => {
port: 8003,
path: '/reset-mock-server',
method: 'POST',
agent: false,
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData)
Expand Down Expand Up @@ -120,19 +121,62 @@ const resetMockServer = async () => {
}
};

const originalBeforeEach = global.beforeEach;
// Function to end rate limiting
const endRateLimiting = async () => {
try {
const http = require('http');

// Simple HTTP request that properly closes the connection
const postData = '';
const options = {
hostname: 'localhost',
port: 8004,
path: '/end_rate_limiting',
method: 'POST',
agent: false,
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData)
}
};

global.beforeEach = (fn, timeout) => {
originalBeforeEach(async () => {
try {
// Reset the mock server state before each test
await resetMockServer();
const response = await new Promise((resolve, reject) => {
const req = http.request(options, (res) => {
let data = '';
res.on('data', (chunk) => data += chunk);
res.on('end', () => resolve({ status: res.statusCode, data }));
});

// Execute the original beforeEach function
await fn();
} catch (err) {
expect(`beforeEach failed: ${err.message}`).toBe('beforeEach should not fail');
throw err;
req.on('error', reject);
req.on('timeout', () => {
req.destroy();
reject(new Error('Request timeout'));
});

req.setTimeout(5000);
req.write(postData);
req.end();
});

if (response.status !== 200) {
console.warn(`Failed to end rate limiting: ${response.status}`);
}
}, timeout);
} catch (error) {
console.warn(`Could not connect to rate limiting server: ${error.message}`);
}
};

// This hook runs BEFORE each test in every test file.
beforeEach(async () => {
try {
await resetMockServer();
await endRateLimiting();
} catch (error) {
originalConsole.error(
'[jest.setup.js] beforeEach: Failed to reset mock server. ' +
`Error: ${error instanceof Error ? error.message : String(error)}`
);
// Don't throw - allow tests to run even if reset fails
// The internal resetMockServer() already handles errors gracefully
}
});
1 change: 1 addition & 0 deletions mock_devrev_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -378,4 +378,5 @@ async def download_jsonl_gz_file(file_name: str):

if __name__ == "__main__":
import uvicorn
print(f"Starting DevRev server on http://localhost:8003")
uvicorn.run(app, host="localhost", port=8003)
112 changes: 55 additions & 57 deletions run_devrev_snapin_conformance_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ NPM_INSTALL_OUTPUT_FILTER="up to date in|added [0-9]* packages, removed [0-9]* p
ANSI_ESCAPE_PATTERN="s/\x1b\[[0-9;]*[mK]//g"

# Maximum number of characters to display from log files
SNAP_IN_LOG_MAX_CHARS=80000
DEVREV_SERVER_LOG_MAX_CHARS=40000
PROXY_SERVER_LOG_MAX_CHARS=20000
SNAP_IN_LOG_MAX_CHARS=100000
DEVREV_SERVER_LOG_MAX_CHARS=600000
PROXY_SERVER_LOG_MAX_CHARS=30000

# Function to print a log file, truncating it if it's too large
print_log_file() {
Expand Down Expand Up @@ -52,19 +52,13 @@ source "$EXEC_DIR/.env"
set +a # stop automatically exporting

# Function to check and kill any Node process running on port 8000 (React development server)
check_and_kill_node_server() {
check_and_kill_processed_on_port() {
local port=${1:-8000} # Default to port 8000 if no port is provided
# Find process listening on specified port
local pid=$(lsof -i :$port -t 2>/dev/null)
if [ ! -z "$pid" ]; then
if ps -p $pid | grep -q "node"; then
printf "Found server running on port $port. Killing it...\n"
kill $pid 2>/dev/null
sleep 1 # Give the process time to terminate
if [ "${VERBOSE:-}" -eq 1 ] 2>/dev/null; then
printf "Node server terminated.\n"
fi
fi
kill -9 "$pid" 2>/dev/null
fi
}

Expand All @@ -84,10 +78,20 @@ get_children() {

# Function to start the mock DevRev server
start_mock_devrev_server() {
python3 "$SCRIPT_DIR/mock_devrev_server.py" > "$MOCK_DEVREV_SERVER_LOG" 2>&1 &
python3 -u "$SCRIPT_DIR/mock_devrev_server.py" > "$MOCK_DEVREV_SERVER_LOG" 2>&1 &
MOCK_SERVER_PID=$!
sleep 2 # Give the server time to start
printf "\n"

# Wait until the mock DevRev server prints its startup line to the log
while true; do
printf "Waiting for the DevRev server to start...\n"
# If process already died, surface error and logs
if grep -iq -E "Starting DevRev server on|Uvicorn running on" "$MOCK_DEVREV_SERVER_LOG" 2>/dev/null; then
break
fi
sleep 0.1
done

printf "DevRev server is up and running!\n\n"
}

start_proxy_server() {
Expand All @@ -96,11 +100,19 @@ start_proxy_server() {
printf "Error: rate_limiting_proxy.py file not found in $EXEC_DIR/rate_limiting_proxy.py. This file should exist (and should be adopted for 3rd party service's rate limiting response format).\n"
exit 69
fi
python3 "$EXEC_DIR/rate_limiting_proxy.py" > "$PROXY_SERVER_LOG" 2>&1 &
# The -u flag is critical here to disable python's output buffering, ensuring logs are written immediately.
python3 -u "$EXEC_DIR/rate_limiting_proxy.py" > "$PROXY_SERVER_LOG" 2>&1 &
PROXY_SERVER_PID=$!
sleep 2 # Give the server time to start

# Check if the proxy server started successfully.
# Wait until the proxy server prints its startup line to the log
while true; do
printf "Waiting for the proxy server to start...\n"
if grep -iq -E "Starting proxy server on" "$PROXY_SERVER_LOG" 2>/dev/null; then
break
fi
sleep 0.1
done

if ! kill -0 "$PROXY_SERVER_PID" > /dev/null 2>&1; then
wait "$PROXY_SERVER_PID"
EXIT_CODE=$?
Expand All @@ -110,15 +122,16 @@ start_proxy_server() {
exit 69
fi
fi
printf "\n"

printf "Proxy server is up and running!\n\n"
}

# Cleanup function to ensure all processes are terminated
cleanup() {
# Kill any running npm processes started by this script
if [ ! -z "${NPM_PID+x}" ]; then
pkill -P $NPM_PID 2>/dev/null
kill $NPM_PID 2>/dev/null
pkill -9 -P $NPM_PID > /dev/null 2>&1
kill -9 $NPM_PID > /dev/null 2>&1
fi

# Kill React app and its children if they exist
Expand All @@ -127,12 +140,12 @@ cleanup() {
get_children $SNAP_IN_PID

# Kill the main process
kill $SNAP_IN_PID 2>/dev/null
kill -9 $SNAP_IN_PID > /dev/null 2>&1

# Kill all the subprocesses
for pid in "${processes_to_kill[@]}"
do
kill $pid 2>/dev/null
kill -9 $pid > /dev/null 2>&1
done

if [ "${VERBOSE:-}" -eq 1 ] 2>/dev/null; then
Expand All @@ -142,15 +155,15 @@ cleanup() {

# Kill mock DevRev server if it exists
if [ ! -z "${MOCK_SERVER_PID+x}" ]; then
kill $MOCK_SERVER_PID 2>/dev/null
kill -9 $MOCK_SERVER_PID > /dev/null 2>&1
if [ "${VERBOSE:-}" -eq 1 ] 2>/dev/null; then
printf "Mock DevRev server terminated!\n"
fi
fi

# Kill proxy server if it exists
if [ ! -z "${PROXY_SERVER_PID+x}" ]; then
kill $PROXY_SERVER_PID 2>/dev/null
kill -9 $PROXY_SERVER_PID > /dev/null 2>&1
if [ "${VERBOSE:-}" -eq 1 ] 2>/dev/null; then
printf "Proxy server terminated!\n"
fi
Expand All @@ -166,32 +179,15 @@ cleanup() {
trap cleanup EXIT SIGINT SIGTERM

# Check for and kill any existing servers from previous runs
check_and_kill_node_server 8000
check_and_kill_node_server 8002

# Ensure nothing is running on port 8003, then start the mock DevRev server
existing_pids=$(lsof -i :8003 -t 2>/dev/null)
if [ ! -z "$existing_pids" ]; then
printf "Killing existing process(es) on port 8003: %s\n" "$existing_pids"
for pid in $existing_pids; do
kill $pid 2>/dev/null
done
sleep 1
fi
check_and_kill_processed_on_port 8000
check_and_kill_processed_on_port 8002
check_and_kill_processed_on_port 8003
check_and_kill_processed_on_port 8004

start_mock_devrev_server

# Set HTTPS_PROXY environment variable to point to proxy server
export HTTPS_PROXY="http://localhost:8004"

# Ensure nothing is running on port 8004, then start the proxy server
existing_pids_8004=$(lsof -i :8004 -t 2>/dev/null)
if [ ! -z "$existing_pids_8004" ]; then
printf "Killing existing process(es) on port 8004: %s\n" "$existing_pids_8004"
for pid in $existing_pids_8004; do
kill $pid 2>/dev/null
done
sleep 1
fi
start_proxy_server

# Check if chef-cli binary exists at CHEF_CLI_PATH
Expand All @@ -207,9 +203,9 @@ if [ -z "$EXTRACTED_FILES_FOLDER_PATH" ]; then
fi

# Check if EXTRACTED_FILES_FOLDER_PATH does not end with "node_$1/build"
if [[ "$EXTRACTED_FILES_FOLDER_PATH" != *"node_$1/extracted_files" ]]; then
if [[ "$EXTRACTED_FILES_FOLDER_PATH" != *"node_build/extracted_files" ]]; then
echo "Error: EXTRACTED_FILES_FOLDER_PATH should end with 'node_$1/extracted_files'."
echo "Note: The value of EXTRACTED_FILES_FOLDER_PATH should be <path_to_directory_where_you_rendered_the_snap-in>/node_$1/extracted_files."
echo "Note: The value of EXTRACTED_FILES_FOLDER_PATH should be <path_to_directory_where_you_rendered_the_snap-in>/node_build/extracted_files."
exit 69 # EXIT_SERVICE_UNAVAILABLE
fi

Expand Down Expand Up @@ -247,11 +243,11 @@ fi

# Check if the node subfolder exists
if [ -d "$NODE_SUBFOLDER" ]; then
# Find and delete all files and folders except "node_modules", "build", and "package-lock.json"
find "$NODE_SUBFOLDER" -mindepth 1 ! -path "$NODE_SUBFOLDER/node_modules*" ! -path "$NODE_SUBFOLDER/build*" ! -name "package-lock.json" -exec rm -rf {} +
# Find and delete all files and folders except "node_modules"
find "$NODE_SUBFOLDER" -mindepth 1 ! -path "$NODE_SUBFOLDER/node_modules*" -exec rm -rf {} +

if [ "${VERBOSE:-}" -eq 1 ] 2>/dev/null; then
printf "Cleanup completed, keeping 'node_modules' and 'package-lock.json'.\n"
printf "Cleanup completed, keeping 'node_modules'.\n"
fi
else
if [ "${VERBOSE:-}" -eq 1 ] 2>/dev/null; then
Expand Down Expand Up @@ -333,11 +329,11 @@ fi

# Check if the conformance tests node subfolder exists
if [ -d "$NODE_CONFORMANCE_TESTS_SUBFOLDER" ]; then
# Find and delete all files and folders except "node_modules", "build", and "package-lock.json"
find "$NODE_CONFORMANCE_TESTS_SUBFOLDER" -mindepth 1 ! -path "$NODE_CONFORMANCE_TESTS_SUBFOLDER/node_modules*" ! -path "$NODE_CONFORMANCE_TESTS_SUBFOLDER/build*" ! -name "package-lock.json" -exec rm -rf {} +
# Find and delete all files and folders except "node_modules"
find "$NODE_CONFORMANCE_TESTS_SUBFOLDER" -mindepth 1 ! -path "$NODE_CONFORMANCE_TESTS_SUBFOLDER/node_modules*" -exec rm -rf {} +

if [ "${VERBOSE:-}" -eq 1 ] 2>/dev/null; then
printf "Cleanup completed, keeping 'node_modules' and 'package-lock.json'.\n"
printf "Cleanup completed, keeping 'node_modules'.\n"
fi
else
if [ "${VERBOSE:-}" -eq 1 ] 2>/dev/null; then
Expand Down Expand Up @@ -367,19 +363,21 @@ fi

printf "\n#### Running conformance tests...\n"

npm test -- --runInBand --setupFilesAfterEnv="$SCRIPT_DIR/jest.setup.js" --detectOpenHandles 2>&1 | sed -E "$ANSI_ESCAPE_PATTERN"
npm test -- --runInBand --setupFilesAfterEnv="$SCRIPT_DIR/jest.setup.js" --detectOpenHandles --forceExit 2>&1 | sed -E "$ANSI_ESCAPE_PATTERN"
conformance_tests_result=$?

printf "\n#### Output of the DevRev server log file:\n\n"
print_log_file "$MOCK_DEVREV_SERVER_LOG" "$DEVREV_SERVER_LOG_MAX_CHARS"
printf "\n#### Output of The Snap-In log file:\n"
print_log_file "$NODE_SUBFOLDER/app.log" "$SNAP_IN_LOG_MAX_CHARS"
printf "\n"
# uncomment if you need the logs of the proxy server
# printf "\n#### Output of the proxy server log file:\n\n"
# print_log_file "$PROXY_SERVER_LOG" "$PROXY_SERVER_LOG_MAX_CHARS"
printf "\n"

if [ $conformance_tests_result -ne 0 ]; then
if [ "${VERBOSE:-}" -eq 1 ] 2>/dev/null; then
printf "Error: Conformance tests have failed.\n"
fi
exit 2
fi
fi