mirror of
https://dev.iopsys.eu/bbf/icwmp.git
synced 2025-12-10 07:44:41 +01:00
Optimized module test
This commit is contained in:
parent
9322ecdc8b
commit
84021788e6
16 changed files with 91 additions and 188 deletions
|
|
@ -1,21 +1,18 @@
|
|||
variables:
|
||||
DEBUG: 'TRUE'
|
||||
SOURCE_FOLDER: "./src"
|
||||
FLAWFINDER_OPTIONS: "-m 4 --error-level=5"
|
||||
CPPCHECK_OPTIONS: " --enable=all --error-exitcode=1 -D_GNU_SOURCE --suppress=unusedFunction -i ./test/ --inline-suppr"
|
||||
|
||||
include:
|
||||
- project: 'iopsys/gitlab-ci-pipeline'
|
||||
file: '/static-code-analysis.yml'
|
||||
ref: '0.27'
|
||||
ref: '0.30'
|
||||
- project: 'docs/portal2/pipeline-template'
|
||||
file: 'MkDocs.gitlab-ci.yml'
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == "devel"
|
||||
|
||||
variables:
|
||||
DEBUG: 'TRUE'
|
||||
RUN_CPPCHECK: "cppcheck --enable=all --error-exitcode=1 -D_GNU_SOURCE --suppress=unusedFunction -i ./test/ --inline-suppr"
|
||||
SOURCE_FOLDER: "./src"
|
||||
CWMP_WORKER_PROCESSES: 1
|
||||
NBI_WORKER_PROCESSES: 1
|
||||
FS_WORKER_PROCESSES: 1
|
||||
UI_WORKER_PROCESSES: 1
|
||||
|
||||
stages:
|
||||
- static_code_analysis
|
||||
- unit_test
|
||||
|
|
@ -33,32 +30,37 @@ run_unit_test:
|
|||
artifacts:
|
||||
when: always
|
||||
paths:
|
||||
- timestamp
|
||||
- /tmp/memory-report.xml
|
||||
- memory-report.xml
|
||||
- unit-test-coverage.xml
|
||||
|
||||
run_api_test:
|
||||
stage: functional_test
|
||||
image: "${COMMON_IMAGE}"
|
||||
services:
|
||||
- name: dev.iopsys.eu:5050/lcm/swmodd/acs:latest
|
||||
alias: acs
|
||||
allow_failure: false
|
||||
script:
|
||||
- "./gitlab-ci/install-dependencies.sh"
|
||||
- "./gitlab-ci/setup.sh"
|
||||
- "./gitlab-ci/functional-api-test.sh"
|
||||
- "./gitlab-ci/api-test.sh"
|
||||
|
||||
artifacts:
|
||||
when: always
|
||||
reports:
|
||||
junit: ./report/tap.xml
|
||||
paths:
|
||||
- timestamp
|
||||
- api-test-coverage.xml
|
||||
- /tmp/memory-report.xml
|
||||
- memory-report.xml
|
||||
- api-test-result.log
|
||||
|
||||
run_functional_test:
|
||||
stage: functional_test
|
||||
image: "${COMMON_IMAGE}"
|
||||
services:
|
||||
- name: dev.iopsys.eu:5050/lcm/swmodd/acs:latest
|
||||
alias: acs
|
||||
|
||||
allow_failure: false
|
||||
script:
|
||||
- "./gitlab-ci/install-dependencies.sh"
|
||||
|
|
@ -70,10 +72,9 @@ run_functional_test:
|
|||
reports:
|
||||
junit: ./report/tap.xml
|
||||
paths:
|
||||
- timestamp
|
||||
- funl-test-coverage.xml
|
||||
- funl-test-result.log
|
||||
- funl-test-debug.log
|
||||
- /tmp/memory-report.xml
|
||||
- memory-report.xml
|
||||
- memory-report-download.xml
|
||||
- icwmpd_debug.txt
|
||||
|
|
|
|||
|
|
@ -11,18 +11,19 @@ echo "Compiling icmwp"
|
|||
build_icwmp
|
||||
|
||||
mkdir -p /var/state/icwmpd
|
||||
echo "Starting dependent services"
|
||||
|
||||
echo "Starting Services..."
|
||||
cp ./gitlab-ci/icwmp.conf /etc/supervisor/conf.d/
|
||||
supervisorctl reread
|
||||
supervisorctl update
|
||||
supervisorctl restart all
|
||||
sleep 10
|
||||
supervisorctl status all
|
||||
exec_cmd ubus wait_for bbfdm tr069
|
||||
|
||||
# wait until cwmp status is up
|
||||
check_cwmp_status
|
||||
|
||||
echo "Running the api test cases"
|
||||
ubus-api-validator -f ./test/api/json/tr069.validation.json > ./api-test-result.log
|
||||
ubus-api-validator -t 10 -f ./test/api/json/tr069.validation.json > ./api-test-result.log
|
||||
check_ret $?
|
||||
|
||||
sleep 5
|
||||
|
|
@ -40,6 +41,4 @@ exec_cmd tap-junit --input ./api-test-result.log --output report
|
|||
|
||||
check_valgrind_xml
|
||||
|
||||
date +%s > timestamp.log
|
||||
|
||||
echo "Functional API test :: PASS"
|
||||
|
|
@ -11,36 +11,30 @@ trap cleanup SIGINT
|
|||
echo "Compiling icmwp"
|
||||
build_icwmp
|
||||
|
||||
echo "Starting dependent services"
|
||||
supervisorctl update
|
||||
sleep 2
|
||||
supervisorctl restart all
|
||||
sleep 2
|
||||
supervisorctl stop icwmpd
|
||||
sleep 2
|
||||
supervisorctl status all
|
||||
|
||||
echo "Configuring genieacs"
|
||||
configure_genieacs
|
||||
echo "Configuring ACS"
|
||||
configure_acs
|
||||
|
||||
mkdir -p /var/state/icwmpd
|
||||
|
||||
echo "Starting icwmpd deamon"
|
||||
supervisorctl start icwmpd
|
||||
echo "Starting Services..."
|
||||
cp ./gitlab-ci/icwmp.conf /etc/supervisor/conf.d/
|
||||
supervisorctl reread
|
||||
supervisorctl update
|
||||
sleep 10
|
||||
supervisorctl status all
|
||||
|
||||
echo "Checking cwmp status"
|
||||
check_cwmp_status
|
||||
supervisorctl status all
|
||||
|
||||
[ -f funl-test-result.log ] && rm -f funl-test-result.log
|
||||
|
||||
sleep 10
|
||||
echo "## Running script verification of functionalities ##"
|
||||
echo > ./funl-test-result.log
|
||||
echo > ./funl-test-debug.log
|
||||
test_num=0
|
||||
|
||||
for test in $(ls test/script/0*.sh); do
|
||||
for test in $(cat test/script/run_sequence.txt); do
|
||||
test=$(basename ${test})
|
||||
test_num=$(( test_num + 1 ))
|
||||
|
||||
|
|
@ -57,6 +51,7 @@ for test in $(ls test/script/0*.sh); do
|
|||
echo "#### $test Ended with error ####" >> "$icwmp_master_log"
|
||||
echo "#### $test Ended with error ####"
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
echo "Stop all services"
|
||||
|
|
@ -65,9 +60,6 @@ supervisorctl stop icwmpd
|
|||
sleep 10
|
||||
check_valgrind_xml
|
||||
|
||||
cp test/files/etc/config/users /etc/config/
|
||||
cp test/files/etc/config/wireless /etc/config/
|
||||
|
||||
echo "Verify Custom notifications"
|
||||
echo "#### Start custom_notifications ####" >> "$icwmp_master_log"
|
||||
./test/script/verify_custom_notifications.sh
|
||||
|
|
@ -95,6 +87,4 @@ exec_cmd tap-junit --input ./funl-test-result.log --output report
|
|||
sleep 10
|
||||
check_valgrind_xml
|
||||
|
||||
date +%s > timestamp.log
|
||||
|
||||
echo "Functional test :: PASS"
|
||||
|
|
|
|||
7
gitlab-ci/icwmp.conf
Normal file
7
gitlab-ci/icwmp.conf
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
[program:icwmpd]
|
||||
autorestart=false
|
||||
startretries=0
|
||||
numprocs_start=10
|
||||
priority=11
|
||||
command=/bin/bash -c "/usr/bin/valgrind --xml=yes --xml-file=/tmp/memory-report.xml --leak-check=full --show-reachable=yes --show-leak-kinds=all --errors-for-leak-kinds=all --error-exitcode=1 --track-origins=yes /usr/sbin/icwmpd"
|
||||
|
||||
|
|
@ -6,28 +6,8 @@ pwd
|
|||
. ./gitlab-ci/shared.sh
|
||||
|
||||
# install required packages
|
||||
apt update
|
||||
apt install -y mongodb jq uuid-dev libmxml-dev
|
||||
|
||||
# install genieacs
|
||||
exec_cmd npm install -g genieacs@1.2.9
|
||||
ln -sf /root/.nvm/versions/node/v14.16.1/bin/genieacs-cwmp /usr/sbin/genieacs-cwmp
|
||||
ln -sf /root/.nvm/versions/node/v14.16.1/bin/genieacs-fs /usr/sbin/genieacs-fs
|
||||
ln -sf /root/.nvm/versions/node/v14.16.1/bin/genieacs-ui /usr/sbin/genieacs-ui
|
||||
ln -sf /root/.nvm/versions/node/v14.16.1/bin/genieacs-nbi /usr/sbin/genieacs-nbi
|
||||
mkdir -p /data/db
|
||||
apt update > /dev/null 2>&1
|
||||
apt install -y jq uuid-dev libmxml-dev >/dev/null 2>&1
|
||||
|
||||
echo "Installing bbfdmd"
|
||||
install_bbfdmd
|
||||
|
||||
# install usermngr plugin
|
||||
cd -
|
||||
rm -rf /opt/dev/usermngr
|
||||
exec_cmd git clone https://dev.iopsys.eu/iopsys/usermngr.git /opt/dev/usermngr
|
||||
|
||||
echo "Compiling libusermngr"
|
||||
make clean -C /opt/dev/usermngr/src
|
||||
make -C /opt/dev/usermngr/src
|
||||
|
||||
echo "Installing libusermngr"
|
||||
cp -f /opt/dev/usermngr/src/libusermngr.so /usr/lib/bbfdm
|
||||
|
|
|
|||
|
|
@ -1,63 +0,0 @@
|
|||
[program:mongod]
|
||||
autorestart=false
|
||||
startretries=0
|
||||
numprocs_start=0
|
||||
priority=1
|
||||
command=/bin/bash -c "/usr/bin/mongod"
|
||||
|
||||
[program:ubusd]
|
||||
autorestart=false
|
||||
startretries=0
|
||||
numprocs_start=1
|
||||
priority=2
|
||||
command=/bin/bash -c "/usr/sbin/ubusd"
|
||||
|
||||
[program:genieacs_cwmp]
|
||||
autorestart=false
|
||||
startretries=0
|
||||
numprocs_start=4
|
||||
priority=5
|
||||
command=/bin/bash -c "/usr/sbin/genieacs-cwmp"
|
||||
|
||||
[program:genieacs_fs]
|
||||
autorestart=false
|
||||
startretries=0
|
||||
numprocs_start=5
|
||||
priority=6
|
||||
command=/bin/bash -c "/usr/sbin/genieacs-fs"
|
||||
|
||||
[program:genieacs_nbi]
|
||||
autorestart=false
|
||||
startretries=0
|
||||
numprocs_start=6
|
||||
priority=7
|
||||
command=/bin/bash -c "/usr/sbin/genieacs-nbi"
|
||||
|
||||
[program:genieacs_ui]
|
||||
autorestart=false
|
||||
startretries=0
|
||||
numprocs_start=7
|
||||
priority=8
|
||||
command=/bin/bash -c "/usr/sbin/genieacs-ui --ui-jwt-secret secret"
|
||||
|
||||
[program:rpcd]
|
||||
autorestart=true
|
||||
startretries=3
|
||||
numprocs_start=8
|
||||
priority=9
|
||||
command=/bin/bash -c "/usr/sbin/rpcd"
|
||||
|
||||
[program:bbfdmd]
|
||||
autorestart=false
|
||||
startretries=0
|
||||
numprocs_start=9
|
||||
priority=9
|
||||
command=/bin/bash -c "/usr/sbin/bbfdmd"
|
||||
|
||||
[program:icwmpd]
|
||||
autorestart=false
|
||||
startretries=0
|
||||
numprocs_start=10
|
||||
priority=11
|
||||
command=/bin/bash -c "/usr/bin/valgrind --xml=yes --xml-file=/tmp/memory-report.xml --leak-check=full --show-reachable=yes --show-leak-kinds=all --errors-for-leak-kinds=all --error-exitcode=1 --track-origins=yes /usr/sbin/icwmpd"
|
||||
|
||||
|
|
@ -1,28 +1,15 @@
|
|||
[program:ubusd]
|
||||
autorestart=false
|
||||
startretries=0
|
||||
numprocs_start=0
|
||||
priority=1
|
||||
command=/bin/bash -c "/usr/sbin/ubusd"
|
||||
|
||||
[program:download]
|
||||
autorestart=false
|
||||
startretries=0
|
||||
priority=2
|
||||
numprocs_start=1
|
||||
command=/bin/bash -c "cd /tmp/firmware/ && python3 -m http.server 80"
|
||||
|
||||
[program:rpcd]
|
||||
autorestart=true
|
||||
startretries=0
|
||||
numprocs_start=2
|
||||
priority=3
|
||||
priority=2
|
||||
command=/bin/bash -c "/usr/sbin/rpcd"
|
||||
|
||||
[program:download]
|
||||
priority=3
|
||||
command=/bin/bash -c "cd /tmp/firmware/ && python3 -m http.server 80"
|
||||
|
||||
[program:bbfdmd]
|
||||
autorestart=false
|
||||
startretries=0
|
||||
numprocs_start=3
|
||||
priority=4
|
||||
command=/bin/bash -c "/usr/sbin/bbfdmd"
|
||||
|
||||
|
|
@ -5,12 +5,10 @@ pwd
|
|||
|
||||
[ -d "/opt/dev/bbfdm" ] && cd /opt/dev/bbfdm && ./gitlab-ci/setup.sh && cd -
|
||||
rm -rf /etc/supervisor/conf.d/*.conf
|
||||
cp ./gitlab-ci/iopsys-supervisord.conf /etc/supervisor/conf.d/
|
||||
|
||||
cp -rf ./test/files/* /
|
||||
|
||||
echo "set acs url in cwmp uci"
|
||||
url="http://$(hostname -i):7547"
|
||||
echo "set ACS url in cwmp uci"
|
||||
url="http://acs:7547"
|
||||
uci set cwmp.acs.url=$url
|
||||
uci commit cwmp
|
||||
echo "Current ACS URL=$url"
|
||||
|
|
@ -18,3 +16,17 @@ echo "Current ACS URL=$url"
|
|||
# copy schema for validation test
|
||||
cp -r ./schemas/ubus/*.json /usr/share/rpcd/schemas/
|
||||
|
||||
echo "Configure Download Server"
|
||||
mkdir -p /tmp/firmware/
|
||||
dd if=/dev/zero of=/tmp/firmware/firmware_v1.0.bin bs=25MB count=1 >/dev/null 2>&1
|
||||
echo "Valid" > /tmp/firmware/firmware_v1.0.bin
|
||||
|
||||
if=/dev/zero of=/tmp/firmware/invalid_firmware_v1.0.bin bs=25MB count=1 >/dev/null 2>&1
|
||||
echo "Invalid" > /tmp/firmware/invalid_firmware_v1.0.bin
|
||||
|
||||
echo "Starting base services"
|
||||
cp ./gitlab-ci/service-base.conf /etc/supervisor/conf.d/
|
||||
supervisorctl reread
|
||||
supervisorctl update
|
||||
sleep 5
|
||||
supervisorctl status
|
||||
|
|
|
|||
|
|
@ -36,41 +36,29 @@ function exec_cmd()
|
|||
fi
|
||||
}
|
||||
|
||||
function configure_genieacs()
|
||||
function configure_acs()
|
||||
{
|
||||
echo "create a new user"
|
||||
curl -X POST 'http://localhost:3000/init' -H "Content-Type: application/json" --data '{"users": true, "presets": true, "filters": true, "device": true, "index": true, "overview": true}' >/dev/null 2>&1
|
||||
echo "Create a new ACS User"
|
||||
curl -X POST 'http://acs:3000/init' -H "Content-Type: application/json" --data '{"users": true, "presets": true, "filters": true, "device": true, "index": true, "overview": true}' >/dev/null 2>&1
|
||||
check_ret $?
|
||||
|
||||
echo "delete the default provision inform"
|
||||
curl -X DELETE 'http://localhost:7557/provisions/inform' >/dev/null 2>&1
|
||||
echo "Delete the default provision inform from ACS"
|
||||
curl -X DELETE 'http://acs:7557/provisions/inform' >/dev/null 2>&1
|
||||
check_ret $?
|
||||
|
||||
echo "add a new provision inform"
|
||||
curl -X PUT 'http://localhost:7557/provisions/inform' --data-binary '@/tmp/connection_request_auth' >/dev/null 2>&1
|
||||
echo "Add a new provision inform in ACS"
|
||||
curl -X PUT 'http://acs:7557/provisions/inform' --data-binary '@/tmp/connection_request_auth' >/dev/null 2>&1
|
||||
check_ret $?
|
||||
|
||||
#echo "get the supported provisions"
|
||||
#curl -X GET 'http://localhost:7557/provisions/'
|
||||
#curl -X GET 'http://acs:7557/provisions/'
|
||||
#check_ret $?
|
||||
|
||||
echo "upload firmware image to genieacs server"
|
||||
exec_cmd dd if=/dev/zero of=/tmp/firmware_v1.0.bin bs=25MB count=1
|
||||
echo "Valid" > /tmp/firmware_v1.0.bin
|
||||
curl -X PUT 'http://localhost:7557/files/firmware_v1.0.bin' --data-binary '@/tmp/firmware_v1.0.bin' --header "fileType: 1 Firmware Upgrade Image" --header "oui: XXX" --header "productClass: FirstClass" --header "version: 000000001" >/dev/null 2>&1
|
||||
check_ret $?
|
||||
}
|
||||
|
||||
function configure_download_firmware()
|
||||
{
|
||||
echo "Install lighttpd"
|
||||
|
||||
mkdir -p /tmp/firmware/
|
||||
exec_cmd dd if=/dev/zero of=/tmp/firmware/firmware_v1.0.bin bs=25MB count=1
|
||||
echo "Valid" > /tmp/firmware/firmware_v1.0.bin
|
||||
|
||||
exec_cmd dd if=/dev/zero of=/tmp/firmware/invalid_firmware_v1.0.bin bs=25MB count=1
|
||||
echo "Invalid" > /tmp/firmware/invalid_firmware_v1.0.bin
|
||||
#echo "Upload firmware image to ACS server"
|
||||
#exec_cmd dd if=/dev/zero of=/tmp/firmware_v1.0.bin bs=25MB count=1
|
||||
#echo "Valid" > /tmp/firmware_v1.0.bin
|
||||
#curl -X PUT 'http://localhost:7557/files/firmware_v1.0.bin' --data-binary '@/tmp/firmware_v1.0.bin' --header "fileType: 1 Firmware Upgrade Image" --header "oui: XXX" --header "productClass: FirstClass" --header "version: 000000001" >/dev/null 2>&1
|
||||
#check_ret $?
|
||||
}
|
||||
|
||||
function check_cwmp_status()
|
||||
|
|
@ -146,12 +134,14 @@ function install_bbfdmd()
|
|||
fi
|
||||
|
||||
cd /opt/dev/bbfdm
|
||||
./gitlab-ci/install-dependencies.sh install
|
||||
./gitlab-ci/setup.sh install
|
||||
exec_cmd ./gitlab-ci/install-dependencies.sh install
|
||||
exec_cmd ./gitlab-ci/setup.sh install
|
||||
}
|
||||
|
||||
function check_valgrind_xml() {
|
||||
echo "Checking memory leaks..."
|
||||
cp /tmp/memory-report.xml memory-report.xml
|
||||
|
||||
echo "checking UninitCondition"
|
||||
grep -q "<kind>UninitCondition</kind>" /tmp/memory-report.xml
|
||||
error_on_zero $?
|
||||
|
|
|
|||
|
|
@ -9,12 +9,6 @@ trap cleanup SIGINT
|
|||
|
||||
[ -f /etc/icwmpd/cwmp_notifications ] && echo "" >/etc/icwmpd/cwmp_notifications || touch /etc/icwmpd/cwmp_notifications
|
||||
|
||||
echo "Configure download server"
|
||||
configure_download_firmware
|
||||
|
||||
rm /etc/supervisor/conf.d/*.conf
|
||||
cp ./gitlab-ci/iopsys-supervisord-unit.conf /etc/supervisor/conf.d/
|
||||
|
||||
echo "Compiling icmwp"
|
||||
build_icwmp
|
||||
|
||||
|
|
@ -44,6 +38,5 @@ supervisorctl status
|
|||
gcovr -r . 2> /dev/null #throw away stderr
|
||||
# Artefact
|
||||
gcovr -r . 2> /dev/null --xml -o ./unit-test-coverage.xml
|
||||
date +%s > timestamp
|
||||
|
||||
echo "Unit test PASS"
|
||||
|
|
|
|||
|
|
@ -493,7 +493,7 @@ static void ubus_objects_callback(struct ubus_request *req, int type __attribute
|
|||
}
|
||||
|
||||
if (tb[0])
|
||||
result->instance = strdup(blobmsg_get_string(tb[0]));
|
||||
result->instance = CWMP_STRDUP(blobmsg_get_string(tb[0]));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1247,10 +1247,12 @@ int cwmp_handle_rpc_cpe_delete_object(struct rpc *rpc)
|
|||
}
|
||||
FREE(object_name);
|
||||
FREE(parameter_key);
|
||||
FREE(res.instance);
|
||||
cwmp_set_end_session(END_SESSION_RESTART_SERVICES);
|
||||
return 0;
|
||||
|
||||
fault:
|
||||
FREE(res.instance);
|
||||
FREE(object_name);
|
||||
FREE(parameter_key);
|
||||
if (cwmp_create_fault_message(rpc, fault_code, res.fault_msg))
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ sleep 2
|
|||
check_session "GetParameterValues"
|
||||
param_value_after=$(print_tag_value "cwmp:GetParameterValuesResponse" "Value xsi:type=\"xsd:boolean\"")
|
||||
if [ "$param_value_after" != "0" ]; then
|
||||
echo "Error: the value of 'Device.Users.User.1.Enable' is wrong, current_value($param_value_after) expected_value(0)" >> ./funl-test-debug.log
|
||||
echo "Error: the value of 'Device.SSH.Server.1.Enable' is wrong, current_value($param_value_after) expected_value(0)" >> ./funl-test-debug.log
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#!/bin/bash
|
||||
|
||||
connection_request_path="http://localhost:7557/devices/XXX-FirstClass-000000001/tasks?timeout=3000&connection_request"
|
||||
connection_request_path="http://acs:7557/devices/XXX-FirstClass-000000001/tasks?timeout=3000&connection_request"
|
||||
icwmp_log_file="/var/log/icwmpd.log"
|
||||
icwmp_master_log="icwmpd_debug.txt"
|
||||
last_req=0
|
||||
|
|
|
|||
5
test/script/run_sequence.txt
Normal file
5
test/script/run_sequence.txt
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
00_verify_add_method.sh
|
||||
01_verify_delete_method.sh
|
||||
02_verify_get_method.sh
|
||||
03_verify_set_method.sh
|
||||
05_verify_cmd_line.sh
|
||||
|
|
@ -60,7 +60,7 @@ supervisorctl stop icwmpd
|
|||
|
||||
check_valgrind_xml
|
||||
|
||||
notif1=`uci -c /etc/icwmpd get cwmp_notifications.@notifications[0].active | grep "Device.Users."`
|
||||
notif1=`uci -c /etc/icwmpd get cwmp_notifications.@notifications[0].active | grep "Device.SSH."`
|
||||
if [[ $notif1 == *"Device.SSH."* ]]; then
|
||||
echo "FAIL: the json file is invalid, the active notifcation list shouldn't contain Device.SSH. parameter"
|
||||
exit 1
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue