Skip to content

Commit

Permalink
Test issues (#52)
Browse files Browse the repository at this point in the history
* test deletion issue and infinite loop issue fixed

* added formatter for shell scripting

* Added test for dependencies

* dependecy test removed from ci

* redeloy removed from ci

* Deletion test fixed

* startup autodeploy added

* condtion corrected

* dependency issue solved
  • Loading branch information
HeeManSu authored Jun 20, 2024
1 parent 822914e commit f5f2bfe
Show file tree
Hide file tree
Showing 7 changed files with 176 additions and 51 deletions.
11 changes: 6 additions & 5 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@
"source.organizeImports": "explicit",
"source.fixAll": "explicit"
},
"editor.rulers": [
80
],
"editor.rulers": [80],
"editor.quickSuggestions": {
"comments": "on",
"strings": "on",
"other": "on"
},
"editor.suggestOnTriggerCharacters": true
}
"editor.suggestOnTriggerCharacters": true,
"[shellscript]": {
"editor.defaultFormatter": "foxundermoon.shell-format"
}
}
1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ services:
target: test
environment:
TEST_FAAS_STARTUP_DEPLOY: ${TEST_FAAS_STARTUP_DEPLOY:-false}
TEST_FAAS_DEPENDENCY_DEPLOY: ${TEST_FAAS_DEPENDENCY_DEPLOY:-true}
network_mode: host
depends_on:
- faas
Expand Down
75 changes: 64 additions & 11 deletions src/utils/install.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,81 @@
import { promises as fs } from 'fs';
import path from 'path';
import { Resource } from '../app';
import { exec } from './exec';

const createInstallDependenciesScript = (
runner: string,
path: string
): string => {
type Runner = 'python' | 'nodejs' | 'ruby' | 'csharp';

const targetFiles: Record<Runner, string> = {
nodejs: 'package.json',
python: 'requirements.txt',
ruby: 'Gemfile',
csharp: 'project.json'
};

const isRunner = (runner: string): runner is Runner => {
return ['nodejs', 'python', 'ruby', 'csharp'].includes(runner);
};

const findDependencyFile = async (
dir: string,
runner: Runner
): Promise<string | null> => {
const files = await fs.readdir(dir);

for (const file of files) {
const fullPath = path.join(dir, file);
const stat = await fs.stat(fullPath);

if (stat.isDirectory()) {
const result = await findDependencyFile(fullPath, runner);
if (result) return result;
} else if (file === targetFiles[runner]) {
return dir;
}
}

return null;
};

const createInstallDependenciesScript = async (
runner: Runner,
basePath: string
): Promise<string> => {
const dependencyFilePath = await findDependencyFile(basePath, runner);

if (!dependencyFilePath) {
throw new Error(`No ${runner} dependencies file found`);
}

const installDependenciesScript: Record<string, string> = {
python: `cd ${path} && metacall pip3 install -r requirements.txt`,
nodejs: `cd ${path} && metacall npm i`,
ruby: `cd ${path} && metacall bundle install`,
csharp: `cd ${path} && metacall dotnet restore && metacall dotnet release`
python: `cd ${dependencyFilePath} && metacall pip3 install -r requirements.txt`,
nodejs: `cd ${dependencyFilePath} && metacall npm i`,
ruby: `cd ${dependencyFilePath} && metacall bundle install`,
csharp: `cd ${dependencyFilePath} && metacall dotnet restore && metacall dotnet release`
};
return installDependenciesScript[runner];
};

// Todo: Async Error Handling
export const installDependencies = async (
resource: Resource
): Promise<void> => {
if (!resource.runners) return;

for (const runner of resource.runners) {
if (runner == undefined) continue;
else {
await exec(createInstallDependenciesScript(runner, resource.path));
if (runner && isRunner(runner)) {
try {
const script = await createInstallDependenciesScript(
runner,
resource.path
);
await exec(script);
} catch (err) {
console.error(
`Failed to install dependencies for runner ${runner}:`,
err
);
}
}
}
};
19 changes: 19 additions & 0 deletions test/data/python-dependency-app/handler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import requests

# Fetch random joke function
def fetchJoke():
try:
response = requests.get('https://official-joke-api.appspot.com/random_joke')
response.raise_for_status() # Raise an error for bad status codes
joke = response.json()
return {
'setup': joke['setup'],
'punchline': joke['punchline']
}
except requests.RequestException as e:
return {'message': 'Error fetching joke', 'error': str(e)}

# Example usage
if __name__ == "__main__":
joke = fetchJoke()
print(joke)
5 changes: 5 additions & 0 deletions test/data/python-dependency-app/metacall.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"language_id": "py",
"path": ".",
"scripts": ["handler.py"]
}
1 change: 1 addition & 0 deletions test/data/python-dependency-app/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
requests
115 changes: 80 additions & 35 deletions test/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,20 @@

set -exuo pipefail

# Maximum number of retries
MAX_RETRIES=5
RETRY_COUNT=0

# FaaS base URL
BASE_URL="http://localhost:9000"

# #function to check readiness
function check_readiness() {
local status_code
status_code=$(curl -s -o /dev/null -w "%{http_code}" $BASE_URL/readiness)
echo "$status_code"
}

# Get the prefix of a deployment
function getPrefix() {
prefix=$(metacall-deploy --dev --inspect Raw | jq -r ".[] | select(.suffix == \"$1\") | .prefix")
Expand All @@ -38,56 +49,90 @@ function deploy() {
}

# Wait for the FaaS to be ready
while [[ ! $(curl -s -o /dev/null -w "%{http_code}" $BASE_URL/readiness) = "200" ]]; do
while [[ $(check_readiness) != "200" ]]; do
if [[ $RETRY_COUNT -ge $MAX_RETRIES ]]; then
echo "Readiness check failed after $MAX_RETRIES retries."
exit 1
fi
RETRY_COUNT=$((RETRY_COUNT + 1))
sleep 1
done

echo "FaaS ready, starting tests."

# Test deploy (Python) without dependencies
app="python-base-app"
pushd data/$app
# Function to run tests
function run_tests() {
local app=$1
local test_func=$2

pushd data/$app
deploy
prefix=$(getPrefix $app)
url=$BASE_URL/$prefix/$app/v1/call
[[ $(curl -s $url/number) = 100 ]] || exit 1
[[ $(curl -s $url/text) = '"asd"' ]] || exit 1
popd

# Test inspect
echo "Testing inspect functionality."
$test_func $url
popd

# Inspect the deployed projects
inspect_response=$(curl -s $BASE_URL/api/inspect)
# Test inspect
echo "Testing inspect functionality."

# Verify inspection
if [[ $inspect_response != *"$prefix"* ]]; then
echo "Inspection test failed."
exit 1
fi
# Inspect the deployed projects
inspect_response=$(curl -s $BASE_URL/api/inspect)

# Verify packages are included in the response
if [[ $inspect_response != *"packages"* ]]; then
echo "packages not found in inspection response."
exit 1
fi
# Verify inspection
if [[ $inspect_response != *"$prefix"* ]]; then
echo "Inspection test failed."
exit 1
fi

echo "Inspection test passed."
# Verify packages are included in the response
if [[ $inspect_response != *"packages"* ]]; then
echo "packages not found in inspection response."
exit 1
fi

# Test delete only if we are not testing startup deployments
if [[ "${TEST_FAAS_STARTUP_DEPLOY}" == "true" ]]; then
echo "Testing delete functionality."
echo "Inspection test passed."

# Test delete only if we are not testing startup deployments
if [[ "${TEST_FAAS_STARTUP_DEPLOY}" == "true" ]]; then
echo "Testing delete functionality."

# Delete the deployed project
curl -X POST -H "Content-Type: application/json" -d '{"suffix":"'"$app"'","prefix":"'"$prefix"'","version":"v1"}' $BASE_URL/api/deploy/delete

# Verify deletion
if [[ "$app" == "python-dependency-app" ]]; then
if [[ $(curl -s -o /dev/null -w "%{http_code}" $BASE_URL/$prefix/$app/v1/call/fetchJoke) != "404" ]]; then
echo "Deletion test failed."
exit 1
fi
else
if [[ $(curl -s -o /dev/null -w "%{http_code}" $BASE_URL/$prefix/$app/v1/call/number) != "404" ]]; then
echo "Deletion test failed."
exit 1
fi
fi

echo "Deletion test passed."
fi
}

# Delete the deployed project
curl -X POST -H "Content-Type: application/json" -d '{"suffix":"python-base-app","prefix":"'"$prefix"'","version":"v1"}' $BASE_URL/api/deploy/delete
# Test function for python-base-app
function test_python_base_app() {
local url=$1
[[ $(curl -s $url/number) = 100 ]] || exit 1
[[ $(curl -s $url/text) = '"asd"' ]] || exit 1
}

# Verify deletion
if [[ $(curl -s -o /dev/null -w "%{http_code}" $BASE_URL/$prefix/$app/v1/call/number) != "404" ]]; then
echo "Deletion test failed."
exit 1
fi
# Test function for python-dependency-app
function test_python_dependency_app() {
local url=$1
[[ $(curl -s $url/fetchJoke) == *"setup"* && $(curl -s $url/fetchJoke) == *"punchline"* ]] || exit 1
}

echo "Deletion test passed."
# Run tests without dependencies
run_tests "python-base-app" test_python_base_app
if [[ "${TEST_FAAS_DEPENDENCY_DEPLOY}" == "true" ]]; then
run_tests "python-dependency-app" test_python_dependency_app
fi

echo "Integration tests passed without errors."
echo "Integration tests passed without errors."

0 comments on commit f5f2bfe

Please sign in to comment.