Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
erp5
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Alexander Emmerich
erp5
Commits
169ecf6f
Commit
169ecf6f
authored
Oct 12, 2022
by
Thomas Gambier
🚴🏼
Committed by
Lu Xu
Mar 28, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
erp5.util: add a new test type to do real requests to the slapos master
This was previously known as "SlapOS Agent".
parent
a57e0e2f
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
467 additions
and
58 deletions
+467
-58
erp5/util/taskdistribution/__init__.py
erp5/util/taskdistribution/__init__.py
+6
-0
erp5/util/testnode/RealRequestRunner.py
erp5/util/testnode/RealRequestRunner.py
+390
-0
erp5/util/testnode/ScalabilityTestRunner.py
erp5/util/testnode/ScalabilityTestRunner.py
+12
-9
erp5/util/testnode/SlapOSMasterCommunicator.py
erp5/util/testnode/SlapOSMasterCommunicator.py
+28
-16
erp5/util/testnode/UnitTestRunner.py
erp5/util/testnode/UnitTestRunner.py
+3
-6
erp5/util/testnode/Utils.py
erp5/util/testnode/Utils.py
+6
-0
erp5/util/testnode/testnode.py
erp5/util/testnode/testnode.py
+22
-27
No files found.
erp5/util/taskdistribution/__init__.py
View file @
169ecf6f
...
...
@@ -489,6 +489,12 @@ class TaskDistributor(RPCRetry):
"""
return
self
.
_retryRPC
(
'getSlaposHateoasUrl'
)
def
getServiceList
(
self
,
test_suite_title
):
"""
Returns the list of services needed to run the test
"""
return
self
.
_retryRPC
(
'getServiceList'
,
(
test_suite_title
,))
def
createTestResult
(
self
,
revision
,
test_name_list
,
node_title
,
allow_restart
=
False
,
test_title
=
None
,
project_title
=
None
):
"""
...
...
erp5/util/testnode/RealRequestRunner.py
0 → 100644
View file @
169ecf6f
##############################################################################
#
# Copyright (c) 2011 Nexedi SA and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly advised to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import
datetime
import
os
import
subprocess
import
sys
import
time
import
glob
from
.
import
SlapOSControler
,
SlapOSMasterCommunicator
import
json
import
time
import
shutil
import
logging
import
string
import
random
from
six.moves.urllib.parse
import
urlparse
import
base64
from
six.moves
import
http_client
as
httplib
from
.Utils
import
createFolder
,
deunicodeData
,
dealShebang
from
slapos.grid.utils
import
md5digest
import
requests
import
slapos.slap
from
.ProcessManager
import
SubprocessError
,
ProcessManager
,
CancellationError
,
format_command
from
subprocess
import
CalledProcessError
from
.Updater
import
Updater
from
erp5.util
import
taskdistribution
from
erp5.util.benchmark.thread
import
TestThread
# for dummy slapos answer
import
signal
from
.
import
logger
from
six.moves
import
range
# max time to generate frontend instance: 1.5 hour
MAX_FRONTEND_TIME
=
60
*
90
# max time to register instance to slapOSMaster: 5 minutes
MAX_CREATION_INSTANCE_TIME
=
60
*
10
# max time for a test: 20 minutes
MAX_TEST_CASE_TIME
=
60
*
20
# max time to prepare SlapOS for testsuite (software installation, instances requests, etc.)
MAX_PREPARE_TEST_SUITE
=
3600
*
10
*
1.0
# 10 hours
# max time for a test line creation: 5 minutes
MAX_CREATION_TEST_LINE
=
60
*
10
# max time for bootstrapping an instance site
MAX_BOOTSRAPPING_TIME
=
60
*
30
# max time to get a connection
MAX_CONNECTION_TIME
=
60
*
5
# time to check site bootstrap
CHECK_BOOSTRAPPING_TIME
=
60
*
2
# runner names
PERFORMANCE_RUNNER_SCRIPT
=
"performance_tester_erp5"
REQUEST_URL_SCRIPT
=
"requestUrl"
SCALABILITY_TEST
=
"scalability_test"
TEST_SUITE_INIT
=
"__init__.py"
# access SR by password
TESTNODE_USER
=
"testnode"
HTACCESS
=
"/.htaccess"
HTPASSWD
=
"/.htpasswd"
PASSWORD_FILE
=
"/sr_pass"
PASSWORD_LENGTH
=
10
HOSTFILE
=
"/hosts"
SR_DICT
=
"frontend_software_dict"
INSTANCE_DICT
=
"instances_dict"
class
RealRequestRunner
():
def
__init__
(
self
,
testnode
):
self
.
testnode
=
testnode
self
.
slapos_controler
=
SlapOSControler
.
SlapOSControler
(
self
.
testnode
.
working_directory
,
self
.
testnode
.
config
)
# Create the slapos account configuration file and dir
key
=
self
.
testnode
.
taskdistribution
.
getSlaposAccountKey
()
certificate
=
self
.
testnode
.
taskdistribution
.
getSlaposAccountCertificate
()
# Get Slapos Master Url
self
.
slapos_url
=
''
try
:
self
.
slapos_url
=
self
.
testnode
.
taskdistribution
.
getSlaposUrl
()
if
not
self
.
slapos_url
:
self
.
slapos_url
=
self
.
testnode
.
config
[
'server_url'
]
except
Exception
:
self
.
slapos_url
=
self
.
testnode
.
config
[
'server_url'
]
# Get Slapos Master url used for api rest (using hateoas)
self
.
slapos_api_rest_url
=
self
.
testnode
.
taskdistribution
.
getSlaposHateoasUrl
()
logger
.
info
(
"SlapOS Master url is: %s"
,
self
.
slapos_url
)
logger
.
info
(
"SlapOS Master hateoas url is: %s"
,
self
.
slapos_api_rest_url
)
self
.
key_path
,
self
.
cert_path
,
config_path
=
self
.
slapos_controler
.
createSlaposConfigurationFileAccount
(
key
,
certificate
,
self
.
slapos_url
,
self
.
testnode
.
config
)
self
.
slapos_communicator_list
=
[]
# Dict containing all info about SlapOS instances requested for the test
# looks like
# {
# instance1_title: {
#
#
# }
# }
self
.
instances_parameters_dict
=
{}
def
_generateInstanceTitle
(
self
,
service_title
):
"""
Generate an instance title using various parameter
TODO : add some verification (to don't use unexisting variables)
"""
instance_title
=
"E2E.Amarisoft-"
instance_title
+=
"("
+
service_title
+
")-"
instance_title
+=
str
(
datetime
.
datetime
.
now
().
isoformat
())
+
"-"
instance_title
+=
"timestamp="
+
str
(
time
.
time
())
return
instance_title
def
getDictionaryFromFile
(
self
,
dict_file
):
dictionary
=
{}
if
os
.
path
.
isfile
(
dict_file
):
with
open
(
dict_file
,
'r'
)
as
file
:
dictionary
=
json
.
loads
(
file
.
read
())
return
dictionary
def
updateDictionaryFile
(
self
,
dict_file
,
dictionary
):
with
open
(
dict_file
,
'w'
)
as
file
:
file
.
write
(
json
.
dumps
(
dictionary
))
def
_prepareSlapOS
(
self
,
working_directory
,
slapos_instance
,
create_partition
=
1
,
software_path_list
=
None
,
use_local_shared_part
=
False
,
**
kw
):
"""
Launch slapos to build software and partitions
"""
slapproxy_log
=
os
.
path
.
join
(
self
.
testnode
.
config
[
'log_directory'
],
'slapproxy.log'
)
logger
.
debug
(
'Configured slapproxy log to %r'
,
slapproxy_log
)
reset_software
=
slapos_instance
.
retry_software_count
>
10
if
reset_software
:
slapos_instance
.
retry_software_count
=
0
logger
.
info
(
'testnode, retry_software_count: %r'
,
slapos_instance
.
retry_software_count
)
self
.
slapos_controler
.
initializeSlapOSControler
(
slapproxy_log
=
slapproxy_log
,
process_manager
=
self
.
testnode
.
process_manager
,
reset_software
=
reset_software
,
software_path_list
=
software_path_list
)
self
.
testnode
.
process_manager
.
supervisord_pid_file
=
os
.
path
.
join
(
\
self
.
slapos_controler
.
instance_root
,
'var'
,
'run'
,
'supervisord.pid'
)
method_list
=
[
"runSoftwareRelease"
]
if
create_partition
:
method_list
.
append
(
"runComputerPartition"
)
for
method_name
in
method_list
:
slapos_method
=
getattr
(
self
.
slapos_controler
,
method_name
)
logger
.
debug
(
"Before status_dict = slapos_method(...)"
)
status_dict
=
slapos_method
(
self
.
testnode
.
config
,
environment
=
self
.
testnode
.
config
[
'environment'
],
**
kw
)
logger
.
info
(
status_dict
)
logger
.
debug
(
"After status_dict = slapos_method(...)"
)
if
status_dict
[
'status_code'
]
!=
0
:
slapos_instance
.
retry
=
True
slapos_instance
.
retry_software_count
+=
1
raise
SubprocessError
(
status_dict
)
else
:
slapos_instance
.
retry_software_count
=
0
return
status_dict
def
prepareSlapOSForTestNode
(
self
,
test_node_slapos
):
"""
We will build slapos software needed by the testnode itself,
like the building of selenium-runner by default
"""
return
{
'status_code'
:
0
}
def
_initializeSlapOSConnection
(
self
):
"""
Initialize communication with slapos
"""
slap
=
slapos
.
slap
.
slap
()
retry
=
0
while
True
:
# wait until _hateoas_navigator is loaded.
if
retry
>
100
:
break
slap
.
initializeConnection
(
self
.
slapos_url
,
self
.
key_path
,
self
.
cert_path
,
timeout
=
120
,
slapgrid_rest_uri
=
self
.
slapos_api_rest_url
)
if
getattr
(
slap
,
'_hateoas_navigator'
,
None
)
is
None
:
retry
+=
1
logger
.
info
(
"Fail to load _hateoas_navigator waiting a bit and retry."
)
time
.
sleep
(
30
)
else
:
break
if
getattr
(
slap
,
'_hateoas_navigator'
,
None
)
is
None
:
raise
ValueError
(
"Fail to load _hateoas_navigator"
)
supply
=
slap
.
registerSupply
()
order
=
slap
.
registerOpenOrder
()
return
slap
,
supply
,
order
def
prepareSlapOSForTestSuite
(
self
,
node_test_suite
):
"""
Install testsuite softwares
"""
logger
.
debug
(
'Preparing SlapOS for Test Suite...'
)
logger
.
info
(
node_test_suite
)
result
=
self
.
_prepareSlapOS
(
node_test_suite
.
working_directory
,
node_test_suite
,
software_path_list
=
[
node_test_suite
.
custom_profile_path
],
cluster_configuration
=
{
'_'
:
json
.
dumps
(
node_test_suite
.
cluster_configuration
)},
use_local_shared_part
=
True
)
if
result
[
'status_code'
]
!=
0
:
return
result
slappart_directory
=
self
.
testnode
.
config
[
'srv_directory'
].
rsplit
(
"srv"
,
1
)[
0
]
instance_dict_file
=
slappart_directory
+
"var/"
+
INSTANCE_DICT
test_suite
=
node_test_suite
.
test_suite_title
# Initialize communication with slapos
slap
,
supply
,
order
=
self
.
_initializeSlapOSConnection
()
# Destroy previous instances
instance_dict
=
self
.
getDictionaryFromFile
(
instance_dict_file
)
if
test_suite
in
instance_dict
:
instance_list
=
instance_dict
[
test_suite
]
for
instance_title
,
instance_is_shared
in
list
(
instance_list
):
logger
.
info
(
"Destroying previous instance %s"
,
instance_title
)
order
.
request
(
software_release
=
"dummy_SR_just_to_destroy"
,
# XXX empty string is not supported...
partition_reference
=
instance_title
,
shared
=
instance_is_shared
,
state
=
"destroyed"
)
del
instance_list
[
0
]
instance_dict
[
test_suite
]
=
instance_list
self
.
updateDictionaryFile
(
instance_dict_file
,
instance_dict
)
# Get from ERP5 Master the configuration of the cluster for the test
service_list
=
deunicodeData
(
json
.
loads
(
self
.
testnode
.
taskdistribution
.
getServiceList
(
node_test_suite
.
test_suite_title
)))
logger
.
info
(
'List of service is %s'
,
service_list
)
instance_list
=
[]
# instance_list should already be an empty list (but it may not have been initialised if testsuite seen for the first time)
for
service
in
service_list
.
values
():
logger
.
info
(
service
)
instance_title
=
self
.
_generateInstanceTitle
(
service
[
'title'
])
software_release
=
service
[
'url'
]
logger
.
info
(
"Will request instance %s of %s (software_type %s)"
,
instance_title
,
software_release
,
service
[
'software_type'
])
s
=
SlapOSMasterCommunicator
.
SlapOSTester
(
instance_title
,
slap
,
order
,
supply
,
software_release
)
self
.
slapos_communicator_list
.
append
(
s
)
partition_parameter_kw
=
json
.
loads
(
service
[
'partition_parameter_kw'
])
if
len
(
partition_parameter_kw
)
==
1
and
'_'
in
partition_parameter_kw
:
partition_parameter_kw
[
'_'
]
=
json
.
dumps
(
partition_parameter_kw
[
'_'
])
request_kw
=
{
'partition_parameter_kw'
:
partition_parameter_kw
,
'filter_kw'
:
json
.
loads
(
service
[
'filter_kw'
])
}
s
.
requestInstanceStart
(
request_kw
=
request_kw
,
shared
=
service
[
'shared'
],
software_type
=
service
[
'software_type'
]
)
instance_list
.
append
((
instance_title
,
service
[
'shared'
]))
instance_dict
[
test_suite
]
=
instance_list
self
.
updateDictionaryFile
(
instance_dict_file
,
instance_dict
)
logger
.
debug
(
"Instances requested."
)
return
{
'status_code'
:
0
}
def
runTestSuite
(
self
,
node_test_suite
,
portal_url
):
# Wait all instances are started
for
s
in
self
.
slapos_communicator_list
:
try
:
s
.
waitInstanceStarted
()
self
.
instances_parameters_dict
[
s
.
name
]
=
s
.
getInstanceParameterDict
()
except
Exception
as
e
:
error_message
=
"Error starting instance "
+
s
.
name
+
": "
+
str
(
e
)
return
{
'status_code'
:
1
,
'error_message'
:
error_message
}
instances_parameters_file
=
os
.
path
.
join
(
self
.
testnode
.
config
[
'srv_directory'
],
"instances.json"
)
with
open
(
instances_parameters_file
,
'w'
)
as
file
:
file
.
write
(
json
.
dumps
(
self
.
instances_parameters_dict
))
logger
.
debug
(
"ALL INSTANCES CORRECTLY STARTED"
)
config
=
self
.
testnode
.
config
run_test_suite_path_list
=
glob
.
glob
(
self
.
slapos_controler
.
instance_root
+
"/*/bin/runTestSuite"
)
try
:
run_test_suite_path
=
min
(
run_test_suite_path_list
)
except
ValueError
:
raise
ValueError
(
'No runTestSuite provided in installed partitions.'
)
# Deal with Shebang size limitation
invocation_list
=
dealShebang
(
run_test_suite_path
)
invocation_list
+=
(
run_test_suite_path
,
'--master_url'
,
portal_url
,
'--revision'
,
node_test_suite
.
revision
,
'--test_node_title'
,
config
[
'test_node_title'
],
'--test_suite'
,
node_test_suite
.
test_suite
,
'--test_suite_title'
,
node_test_suite
.
test_suite_title
)
soft
=
config
[
'slapos_directory'
]
+
'/soft/'
software_list
=
[
soft
+
md5digest
(
x
)
for
x
in
config
[
'software_list'
]]
PATH
=
os
.
getenv
(
'PATH'
,
''
)
PATH
=
':'
.
join
(
x
+
'/bin'
for
x
in
software_list
)
+
(
PATH
and
':'
+
PATH
)
SLAPOS_TEST_SHARED_PART_LIST
=
os
.
pathsep
.
join
(
self
.
slapos_controler
.
shared_part_list
)
SLAPOS_TEST_LOG_DIRECTORY
=
node_test_suite
.
log_folder_path
supported_parameter_set
=
set
(
self
.
testnode
.
process_manager
.
getSupportedParameterList
(
run_test_suite_path
))
def
path
(
name
,
compat
):
# BBB
path
,
=
filter
(
os
.
path
.
exists
,
(
base
+
relative
for
relative
in
(
'/bin/'
+
name
,
'/parts/'
+
compat
)
for
base
in
software_list
))
return
path
for
option
,
value
in
(
(
'--firefox_bin'
,
lambda
:
path
(
'firefox'
,
'firefox/firefox-slapos'
)),
(
'--frontend_url'
,
lambda
:
config
[
'frontend_url'
]),
(
'--node_quantity'
,
lambda
:
config
[
'node_quantity'
]),
(
'--xvfb_bin'
,
lambda
:
path
(
'xvfb'
,
'xserver/bin/Xvfb'
)),
(
'--project_title'
,
lambda
:
node_test_suite
.
project_title
),
(
'--shared_part_list'
,
lambda
:
SLAPOS_TEST_SHARED_PART_LIST
),
(
'--log_directory'
,
lambda
:
SLAPOS_TEST_LOG_DIRECTORY
),
):
if
option
in
supported_parameter_set
:
invocation_list
+=
option
,
value
()
# TODO : include testnode correction ( b111682f14890bf )
if
hasattr
(
node_test_suite
,
'additional_bt5_repository_id'
):
additional_bt5_path
=
os
.
path
.
join
(
node_test_suite
.
working_directory
,
node_test_suite
.
additional_bt5_repository_id
)
invocation_list
.
extend
([
"--bt5_path"
,
additional_bt5_path
])
# From this point, test runner becomes responsible for updating test
# result. We only do cleanup if the test runner itself is not able
# to run.
createFolder
(
node_test_suite
.
test_suite_directory
,
clean
=
True
)
# Log the actual command with root logger
root_logger
=
logging
.
getLogger
()
root_logger
.
info
(
"Running test suite with: %s"
,
format_command
(
*
invocation_list
,
PATH
=
PATH
))
def
hide_distributor_url
(
s
):
# type: (bytes) -> bytes
return
s
.
replace
(
portal_url
.
encode
(
'utf-8'
),
b'$DISTRIBUTOR_URL'
)
self
.
testnode
.
process_manager
.
spawn
(
*
invocation_list
,
PATH
=
PATH
,
SLAPOS_TEST_SHARED_PART_LIST
=
SLAPOS_TEST_SHARED_PART_LIST
,
SLAPOS_TEST_LOG_DIRECTORY
=
SLAPOS_TEST_LOG_DIRECTORY
,
SLAPOS_INSTANCES_PARAMETERS_FILE
=
instances_parameters_file
,
cwd
=
node_test_suite
.
test_suite_directory
,
log_prefix
=
'runTestSuite'
,
output_replacers
=
(
hide_distributor_url
,),
get_output
=
False
)
return
{
'status_code'
:
0
}
def
getRelativePathUsage
(
self
):
"""
Used by the method testnode.constructProfile() to know
if the software.cfg have to use relative path or not.
"""
return
False
erp5/util/testnode/ScalabilityTestRunner.py
View file @
169ecf6f
...
...
@@ -386,10 +386,11 @@ Require valid-user
self
.
error_message
=
test_configuration
[
'error_message'
]
self
.
randomized_path
=
test_configuration
[
'randomized_path'
]
if
not
self
.
launchable
:
logger
.
info
(
"Test suite %s is not actually launchable"
" with the current cluster configuration."
,
node_test_suite
.
test_suite_title
)
logger
.
info
(
"ERP5 Master indicates : %s"
,
self
.
error_message
)
return
{
'status_code'
:
1
}
error_message
=
(
"Test suite %s is not actually launchable"
" with the current cluster configuration.
\
n
"
"ERP5 Master indicates : %s"
%
(
node_test_suite
.
test_suite_title
,
self
.
error_message
))
logger
.
info
(
error_message
)
return
{
'status_code'
:
1
,
'error_message'
:
error_message
}
configuration_list
=
test_configuration
[
'configuration_list'
]
configuration
=
configuration_list
[
0
]
...
...
@@ -451,8 +452,9 @@ Require valid-user
self
.
_comeBackFromDummySlapOS
()
if
self
.
remainSoftwareToInstall
()
:
# All softwares are not installed, however maxtime is elapsed, that's a failure.
logger
.
error
(
"All softwares are not installed."
)
return
{
'status_code'
:
1
}
error_message
=
"All softwares are not installed."
logger
.
error
(
error_message
)
return
{
'status_code'
:
1
,
'error_message'
:
error_message
}
logger
.
debug
(
"All software installed."
)
# even if we re-use existing setup we need proper configuration applied
...
...
@@ -469,11 +471,12 @@ Require valid-user
purge_previous_instance
=
not
self
.
use_existing_setup
)
logger
.
debug
(
"Scalability instance requested."
)
except
Exception
as
e
:
logger
.
error
(
"Error creating instance: "
+
str
(
e
))
return
{
'status_code'
:
1
}
error_message
=
"Error creating instance: "
+
str
(
e
)
logger
.
error
(
error_message
)
return
{
'status_code'
:
1
,
'error_message'
:
error_message
}
return
{
'status_code'
:
0
}
return
{
'status_code'
:
1
}
return
{
'status_code'
:
1
,
'error_message'
:
"Software installation too long or error(s) are present during SR install."
}
def
makeSuite
(
self
,
test_suite
,
location_list
,
**
kwargs
):
import
imp
...
...
erp5/util/testnode/SlapOSMasterCommunicator.py
View file @
169ecf6f
from
__future__
import
print_function
import
datetime
import
feedparser
import
json
import
traceback
import
time
...
...
@@ -71,6 +72,8 @@ class SlapOSMasterCommunicator(object):
self
.
slap_order
=
slap_order
self
.
slap_supply
=
slap_supply
self
.
hateoas_navigator
=
self
.
slap
.
_hateoas_navigator
self
.
message_history
=
[]
self
.
computer_guid
=
""
if
url
is
not
None
and
\
url
.
startswith
(
SOFTWARE_PRODUCT_NAMESPACE
):
...
...
@@ -79,7 +82,7 @@ class SlapOSMasterCommunicator(object):
try
:
url
=
product
.
__getattr__
(
url
[
len
(
SOFTWARE_PRODUCT_NAMESPACE
):])
except
AttributeError
as
e
:
logger
.
warning
(
'Error on get software release: %s '
,
e
.
message
)
logger
.
warning
(
"Error on get software release: {}"
.
format
(
e
)
)
self
.
url
=
url
...
...
@@ -115,6 +118,7 @@ class SlapOSMasterCommunicator(object):
partition_reference
=
self
.
name
,
shared
=
shared
,
state
=
state
,
software_type
=
software_type
,
**
self
.
request_kw
)
@
retryOnNetworkFailure
...
...
@@ -183,16 +187,18 @@ class SlapOSMasterCommunicator(object):
message_list
=
[]
try
:
for
instance
in
self
.
getInstanceUrlList
():
# we need to explicitly encode as utf-8 the unicode string we get
instance
[
"text_content"
]
=
instance
[
"text_content"
].
encode
(
'utf8'
)
logger
.
info
(
'in _getInstanceState, viewing instance'
)
logger
.
info
(
instance
)
news
=
instance
[
'SoftwareInstance_getNewsDict'
]
state
=
INSTANCE_STATE_UNKNOWN
monitor_information_dict
=
{}
is_slave
=
instance
[
'portal_type'
]
==
"Slave Instance"
if
is_slave
:
if
len
(
instance
[
'getConnectionXmlAsDict'
])
>
0
:
state
=
INSTANCE_STATE_STARTED
# XXX for now consider a slave as always ready because in ORS software
# there is no information published in the slave
#if len(instance['getConnectionXmlAsDict']) > 0:
state
=
INSTANCE_STATE_STARTED
else
:
# not slave
instance_state
=
news
...
...
@@ -300,7 +306,6 @@ class SlapOSTester(SlapOSMasterCommunicator):
self
.
request_kw
=
json
.
loads
(
request_kw
)
else
:
self
.
request_kw
=
request_kw
self
.
message_history
=
[]
def
getInfo
(
self
):
info
=
""
...
...
@@ -323,12 +328,13 @@ class SlapOSTester(SlapOSMasterCommunicator):
def
requestInstanceStop
(
self
,
instance_title
=
None
,
request_kw
=
None
,
shared
=
False
,
software_type
=
"RootSoftwareInstance"
):
self
.
instance
=
self
.
_request
(
INSTANCE_STATE_STOPPED
,
instance_title
,
request_kw
,
shared
,
software_type
)
def
requestInstanceDestroy
(
self
,
instance_title
=
None
,
request_kw
=
None
,
shared
=
False
):
def
requestInstanceDestroy
(
self
):
# TODO remove this function
self
.
destroyInstance
()
def
waitInstanceStarted
(
self
,
instance_title
=
None
):
if
not
instance_title
:
instance_title
=
self
.
name
self
.
destroyInstance
(
instance_title
)
def
waitInstanceStarted
(
self
,
instance_title
):
error_message
=
self
.
_waitInstance
(
instance_title
,
INSTANCE_STATE_STARTED
)[
"error_message"
]
if
error_message
is
not
None
:
logger
.
error
(
error_message
)
...
...
@@ -349,6 +355,13 @@ class SlapOSTester(SlapOSMasterCommunicator):
logger
.
error
(
error_message
)
raise
ValueError
(
error_message
)
def
getInstanceParameterDict
(
self
):
for
instance
in
self
.
getInstanceUrlList
():
if
instance
[
"title"
]
==
self
.
name
:
return
instance
[
"getConnectionXmlAsDict"
]
return
{}
def
getMasterFrontendDict
(
self
):
def
getInstanceGuid
():
try
:
...
...
@@ -365,7 +378,7 @@ class SlapOSTester(SlapOSMasterCommunicator):
pass
start_time
=
time
.
time
()
while
not
getInstanceGuid
()
and
time
.
time
()
-
start_time
<
60
*
5
:
sleep
(
60
)
time
.
sleep
(
60
)
return
{
'instance_guid'
:
getInstanceGuid
(),
'frontend_master_ipv6'
:
frontend_master_ipv6
}
# XXX TODO
...
...
@@ -406,16 +419,15 @@ class SlapOSTester(SlapOSMasterCommunicator):
'frontend-url-list'
:
frontend_url_list
,
\
'balancer-user-v6'
:
balancer_user_v6
}
def
destroyInstance
(
self
,
instance_title
):
self
.
name
=
instance_title
def
destroyInstance
(
self
):
instance_url_list
=
self
.
getInstanceUrlList
()
if
instance_url_list
:
for
instance
in
instance_url_list
:
if
instance
[
"title"
]
!=
instance_titl
e
:
if
instance
[
"title"
]
!=
self
.
nam
e
:
self
.
_request
(
INSTANCE_STATE_DESTROYED
,
instance
[
"title"
])
else
:
root_instance
=
instance
logger
.
info
(
"Going to destroy root partition: "
+
str
(
instance_titl
e
))
logger
.
info
(
"Going to destroy root partition: "
+
str
(
self
.
nam
e
))
self
.
_request
(
INSTANCE_STATE_DESTROYED
,
root_instance
[
"title"
])
else
:
logger
.
info
(
"Instance not found"
)
...
...
@@ -537,7 +549,7 @@ class SoftwareReleaseTester(SlapOSTester):
deadline
=
self
.
deadline
if
deadline
<
now
and
deadline
is
not
None
:
raise
TestTimeout
(
self
.
state
)
raise
Exception
(
"Test timeout (current state is {})."
.
format
(
self
.
state
)
)
_
,
_
,
next_state
,
software_state
,
instance_state
=
self
.
transition_dict
[
self
.
state
]
...
...
erp5/util/testnode/UnitTestRunner.py
View file @
169ecf6f
...
...
@@ -32,14 +32,10 @@ import logging
from
.
import
logger
from
.ProcessManager
import
SubprocessError
,
format_command
from
.SlapOSControler
import
SlapOSControler
from
.Utils
import
createFolder
from
.Utils
import
createFolder
,
dealShebang
from
slapos.grid.utils
import
md5digest
def
dealShebang
(
run_test_suite_path
):
with
open
(
run_test_suite_path
)
as
f
:
if
f
.
read
(
2
)
==
'#!'
:
return
f
.
readline
().
split
(
None
,
1
)
return
[]
class
UnitTestRunner
(
object
):
...
...
@@ -203,6 +199,7 @@ class UnitTestRunner(object):
log_prefix
=
'runTestSuite'
,
output_replacers
=
(
hide_distributor_url
,),
get_output
=
False
)
return
{
'status_code'
:
0
}
def
getRelativePathUsage
(
self
):
"""
...
...
erp5/util/testnode/Utils.py
View file @
169ecf6f
...
...
@@ -10,6 +10,12 @@ def createFolder(folder, clean=False):
rmtree
(
folder
)
os
.
mkdir
(
folder
)
def
dealShebang
(
run_test_suite_path
):
with
open
(
run_test_suite_path
)
as
f
:
if
f
.
read
(
2
)
==
'#!'
:
return
f
.
readline
().
split
(
None
,
1
)
return
[]
if
six
.
PY3
:
def
deunicodeData
(
data
):
return
data
...
...
erp5/util/testnode/testnode.py
View file @
169ecf6f
...
...
@@ -38,6 +38,7 @@ from subprocess import CalledProcessError
from
.Updater
import
Updater
from
.NodeTestSuite
import
NodeTestSuite
,
SlapOSInstance
from
.ScalabilityTestRunner
import
ScalabilityTestRunner
from
.RealRequestRunner
import
RealRequestRunner
from
.UnitTestRunner
import
UnitTestRunner
from
.Utils
import
deunicodeData
from
..
import
taskdistribution
...
...
@@ -49,6 +50,7 @@ PROFILE_PATH_KEY = 'profile_path'
test_type_registry
=
{
'UnitTest'
:
UnitTestRunner
,
'ScalabilityTest'
:
ScalabilityTestRunner
,
'SlapOSAgentTest'
:
RealRequestRunner
}
class
TestNode
(
object
):
...
...
@@ -106,13 +108,13 @@ class TestNode(object):
# Absolute path to relative path
software_config_path
=
os
.
path
.
join
(
repository_path
,
profile_path
)
if
use_relative_path
:
if
use_relative_path
:
from_path
=
os
.
path
.
join
(
self
.
working_directory
,
node_test_suite
.
reference
)
software_config_path
=
os
.
path
.
relpath
(
software_config_path
,
from_path
)
# Construct sections
if
not
(
buildout_section_id
is
None
)
:
if
buildout_section_id
is
not
None
:
# Absolute path to relative
if
use_relative_path
:
from_path
=
os
.
path
.
join
(
self
.
working_directory
,
...
...
@@ -320,7 +322,7 @@ shared = true
testnode_software_successfully_built
=
True
logger
.
info
(
"Will now skip build of testnode software"
)
# Clean-up test suites
self
.
purgeOldTestSuite
(
test_suite_data
)
#
self.purgeOldTestSuite(test_suite_data)
for
test_suite
in
test_suite_data
:
node_test_suite
=
self
.
getNodeTestSuite
(
test_suite
.
pop
(
"test_suite_reference"
))
...
...
@@ -354,6 +356,8 @@ shared = true
generated_config
=
taskdistributor
.
generateConfiguration
(
node_test_suite
.
test_suite_title
)
json_data
=
json
.
loads
(
generated_config
)
logger
.
info
(
"DEBUG JSON"
)
logger
.
info
(
json_data
)
cluster_configuration
=
deunicodeData
(
json_data
[
'configuration_list'
][
0
])
node_test_suite
.
edit
(
cluster_configuration
=
cluster_configuration
)
# Now prepare the installation of SlapOS and create instance
...
...
@@ -364,35 +368,26 @@ shared = true
# should be at the same revision, so it is safe to prune orphan
# objects now.
git_gc_auto
()
def
report_error
(
error_message
):
test_result
.
reportFailure
(
stdout
=
error_message
)
logger
.
error
(
error_message
)
raise
ValueError
(
error_message
)
if
status_dict
[
'status_code'
]
==
1
:
report_error
(
status_dict
.
get
(
'error_message'
)
or
"Error during prepareSlapOSForTestSuite"
)
# Give some time so computer partitions may start
# as partitions can be of any kind we have and likely will never have
# a reliable way to check if they are up or not ...
time
.
sleep
(
20
)
# XXX: Do not switch according to the test type. IOW, the
# following code must be moved to the test type class.
if
my_test_type
==
'UnitTest'
:
runner
.
runTestSuite
(
node_test_suite
,
portal_url
)
elif
my_test_type
==
'ScalabilityTest'
:
error_message
=
None
# A problem is appeared during runTestSuite
if
status_dict
[
'status_code'
]
==
1
:
error_message
=
"Software installation too long or error(s) are present during SR install."
else
:
status_dict
=
runner
.
runTestSuite
(
node_test_suite
,
portal_url
)
# A problem is appeared during runTestSuite
if
status_dict
[
'status_code'
]
==
1
:
error_message
=
status_dict
[
'error_message'
]
# If an error is appeared
if
error_message
:
test_result
.
reportFailure
(
stdout
=
error_message
)
logger
.
error
(
error_message
)
raise
ValueError
(
error_message
)
else
:
raise
NotImplementedError
# break the loop to get latest priorities from master
runner
.
runTestSuite
(
node_test_suite
,
portal_url
)
status_dict
=
runner
.
runTestSuite
(
node_test_suite
,
portal_url
)
# A problem is appeared during runTestSuite
if
status_dict
[
'status_code'
]
==
1
:
report_error
(
status_dict
.
get
(
'error_message'
)
or
'Error during runTestSuite'
)
break
except
(
SubprocessError
,
CalledProcessError
,
ConnectionError
)
as
e
:
logger
.
exception
(
""
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment