Commit 9c297883 authored by Kirill Smelkov's avatar Kirill Smelkov

Merge branch 'x/lte-multiru' into xy/lte-multiru

1) get generic tests into shape

2) fix instantiation when refrences contain spaces and/or other special characters.
   link to discussion: d5d4f7c8 (comment 196869)

3) fix schemas:
   * ru: mac_addr becomes common CPRI property instead of being Lopcomm-specific
   * ue/cell/nr: ssb_nr_arfcn is fixed to be optional, similarly to cell/nr
parents dc47d24f dcd40c25
......@@ -24,11 +24,11 @@ md5sum = f5c76c3443b75569eb18503dce38e783
[slaplte.jinja2]
_update_hash_filename_ = slaplte.jinja2
md5sum = 8c044b28682940fbca62657c16613157
md5sum = fa841e105d78aab36b9ea205a69608fb
[ru_libinstance.jinja2.cfg]
_update_hash_filename_ = ru/libinstance.jinja2.cfg
md5sum = 031805301916a7d17a6a8fb31914cbea
md5sum = 4c1e6fbd774042cdd12687fd30635c6b
[ru_sdr_libinstance.jinja2.cfg]
_update_hash_filename_ = ru/sdr/libinstance.jinja2.cfg
......@@ -36,7 +36,7 @@ md5sum = b7906ca3a6b17963f78f680fc0842b74
[ru_lopcomm_libinstance.jinja2.cfg]
_update_hash_filename_ = ru/lopcomm/libinstance.jinja2.cfg
md5sum = 409ab889d75ec260aa0e52548463a38f
md5sum = 667bf3d0af1ae3e6d740c667957449dc
[ru_sunwave_libinstance.jinja2.cfg]
_update_hash_filename_ = ru/sunwave/libinstance.jinja2.cfg
......@@ -80,7 +80,7 @@ md5sum = 2b8b57c5771b2a2203c0e7767e629e55
[ru_xbuildout.py]
_update_hash_filename_ = ru/xbuildout.py
md5sum = b9aa7356ebccfb1e9d2324106ad88485
md5sum = 2856e18a18eb8f0af090cfd714e1973a
[ru_capdo.c]
_update_hash_filename_ = ru/capdo.c
......@@ -88,7 +88,7 @@ md5sum = 52da9fe3a569199e35ad89ae1a44c30e
[template-enb]
_update_hash_filename_ = instance-enb.jinja2.cfg
md5sum = 143f9b0e9866d37e6527e89f74b4ef1c
md5sum = 29b5a5a61b0498681d480726be9e56bf
[template-ors-enb]
_update_hash_filename_ = instance-ors-enb.jinja2.cfg
......@@ -100,7 +100,7 @@ md5sum = c807be73b9304f5a4c7483a3776bbc17
[template-ue]
_update_hash_filename_ = instance-ue.jinja2.cfg
md5sum = aa6b8e50bd8d9c4cc6e23b01a2be5644
md5sum = be16ae9b38dd4e46c09bc9eb4bb7eb93
[template-obsolete]
_update_hash_filename_ = instance-obsolete.jinja2.cfg
......@@ -112,7 +112,7 @@ md5sum = dcaac06553a3222b14c0013a13f4a149
[enb.jinja2.cfg]
filename = config/enb.jinja2.cfg
md5sum = a8e67b3c9373fe4d97066a64d1ff8a98
md5sum = 7edbafa743dc17749ff910aca775abbf
[drb_lte.jinja2.cfg]
filename = config/drb_lte.jinja2.cfg
......@@ -145,7 +145,7 @@ md5sum = 36281b03597252cf75169417d02fc28c
[ue.jinja2.cfg]
filename = config/ue.jinja2.cfg
md5sum = 9bffa00d88ffa57cf1e3b11a24c494b9
md5sum = 62291a11fd36a42464901cdc81338687
[ru_lopcomm_CreateProcessingEle.jinja2.xml]
_update_hash_filename_ = ru/lopcomm/CreateProcessingEle.jinja2.xml
......@@ -153,7 +153,7 @@ md5sum = e435990eb0a0d4be41efa9bd16dce09b
[ru_lopcomm_cu_config.jinja2.xml]
_update_hash_filename_ = ru/lopcomm/cu_config.jinja2.xml
md5sum = 274faf246197cbdd4973b772569daa8e
md5sum = 346c911e1ac5e5001a39c8926b44c91e
[software.cfg.html]
_update_hash_filename_ = gadget/software.cfg.html
......
{%- import 'slaplte.jinja2' as slaplte with context %}
{%- set B = slaplte.B %}
{%- set J = slaplte.J %}
{%- set jcell_ru_ref = slaplte.jcell_ru_ref %}
{%- set cfg = slaplte.cfg %}
{#- for standalone testing via slapos-render-config.py
NOTE: keep in sync with instance-enb.jinja2.cfg and ru/libinstance.jinja2.cfg #}
......@@ -35,13 +35,13 @@
{
{%- if cell2.cell_type == 'lte' %}
rat: "eutra",
cell_id: {{ slapparameter_dict.enb_id }}{{ cell2.cell_id.removeprefix('0x') }}, // -> {{ cell2_ref }}
cell_id: {{ slapparameter_dict.enb_id }}{{ cell2.cell_id.removeprefix('0x') }}, // -> {{ B(cell2_ref) }}
n_id_cell: {{ cell2.pci }},
dl_earfcn: {{ cell2.dl_earfcn }},
tac: {{ cell2.tac }},
{%- elif cell2.cell_type == 'nr' %}
rat: "nr",
cell_id: {{ cell2.cell_id }}, // -> {{ cell2_ref }}
cell_id: {{ cell2.cell_id }}, // -> {{ B(cell2_ref) }}
{%- else %}
{%- do bug('unreachable') %}
{%- endif %}
......@@ -58,13 +58,13 @@
{
{%- if ncell.cell_type == 'lte' %}
rat: "eutra",
cell_id: {{ ncell.e_cell_id }}, // -> {{ peercell_ref }}
cell_id: {{ ncell.e_cell_id }}, // -> {{ B(peercell_ref) }}
n_id_cell: {{ ncell.pci }},
dl_earfcn: {{ ncell.dl_earfcn }},
tac: {{ ncell.tac }},
{%- elif ncell.cell_type == 'nr' %}
rat: "nr",
nr_cell_id: {{ ncell.nr_cell_id }}, // -> {{ peercell_ref }}
nr_cell_id: {{ ncell.nr_cell_id }}, // -> {{ B(peercell_ref) }}
gnb_id_bits: {{ ncell.gnb_id_bits }},
n_id_cell: {{ ncell.pci }},
dl_nr_arfcn: {{ ncell.dl_nr_arfcn }},
......@@ -184,7 +184,7 @@
{%- set iru = iru_dict[ru_ref] %}
{%- set ru = iru['_'] %}
// {{ cell_ref }} ({{ ru_ref }})
// {{ B(cell_ref) }} ({{ B(ru_ref) }})
{
rf_port: {{ ru._rf_port }},
n_antenna_dl: {{ ru.n_antenna_dl }},
......@@ -208,7 +208,7 @@
{%- set cell2 = icell2['_'] %}
{%- if cell2_ref != cell_ref and cell2.cell_type == 'lte' %}
{
cell_id: {{ cell2.cell_id }}, // + {{ cell2_ref }}
cell_id: {{ cell2.cell_id }}, // + {{ B(cell2_ref) }}
cross_carrier_scheduling: false,
},
{%- endif %}
......@@ -222,7 +222,7 @@
{%- set cell2 = icell2['_'] %}
{%- if cell2_ref != cell_ref and cell2.cell_type == 'nr' %}
{
cell_id: {{ cell2.cell_id }}, // + {{ cell2_ref }}
cell_id: {{ cell2.cell_id }}, // + {{ B(cell2_ref) }}
},
{%- endif %}
{%- endfor %}
......@@ -298,11 +298,11 @@
manual_ref_signal_power: true,
{%- endif %}
drb_config: "{{ cell_ref }}-drb.cfg",
drb_config: "{{ B('%s-drb.cfg' % cell_ref) }}",
sib_sched_list: [
{
filename: "{{ cell_ref }}-sib23.asn",
filename: "{{ B('%s-sib23.asn' % cell_ref) }}",
si_periodicity: 16,
},
],
......@@ -421,7 +421,7 @@
{%- set iru = iru_dict[ru_ref] %}
{%- set ru = iru['_'] %}
// {{ cell_ref }} ({{ ru_ref }})
// {{ B(cell_ref) }} ({{ B(ru_ref) }})
{
rf_port: {{ ru._rf_port }},
n_antenna_dl: {{ ru.n_antenna_dl }},
......@@ -450,7 +450,7 @@
{%- set cell2 = icell2['_'] %}
{%- if cell2_ref != cell_ref and cell2.cell_type == 'nr' %}
{
cell_id: {{ cell2.cell_id }}, // + {{ cell2_ref }}
cell_id: {{ cell2.cell_id }}, // + {{ B(cell2_ref) }}
},
{%- endif %}
{%- endfor %}
......@@ -698,7 +698,7 @@
},
drb_config: "{{ cell_ref }}-drb.cfg",
drb_config: "{{ B('%s-drb.cfg' % cell_ref) }}",
},
{%- endif %}
......
......@@ -48,7 +48,7 @@
// LTE cells
cell_list: [
// CELL_a (RU1)
// CELL__a (RU1)
{
rf_port: 0,
n_antenna_dl: 2,
......@@ -68,7 +68,7 @@
// Intra-ENB HO
{
rat: "nr",
cell_id: 0x02, // -> CELL_b
cell_id: 0x02, // -> CELL__b
},
// Inter-ENB HO
......@@ -102,7 +102,7 @@
// Dual Connectivity: LTE + NR
en_dc_scg_cell_list: [
{
cell_id: 0x02, // + CELL_b
cell_id: 0x02, // + CELL__b
},
],
......@@ -140,11 +140,11 @@
srs_hopping_bandwidth: 0,
},
drb_config: "CELL_a-drb.cfg",
drb_config: "CELL__a-drb.cfg",
sib_sched_list: [
{
filename: "CELL_a-sib23.asn",
filename: "CELL__a-sib23.asn",
si_periodicity: 16,
},
],
......@@ -242,7 +242,7 @@
// NR cells
nr_cell_list: [
// CELL_b (RU2)
// CELL__b (RU2)
{
rf_port: 1,
n_antenna_dl: 2,
......@@ -267,7 +267,7 @@
// Intra-ENB HO
{
rat: "eutra",
cell_id: 0x1001201, // -> CELL_a
cell_id: 0x1001201, // -> CELL__a
n_id_cell: 1,
dl_earfcn: 38050,
tac: 0x1234,
......@@ -438,7 +438,7 @@
},
drb_config: "CELL_b-drb.cfg",
drb_config: "CELL__b-drb.cfg",
},
],
......
......@@ -12,8 +12,8 @@
// XXX vvv <- ru.txrx_active ? XXX how to handle txrx_active for SDR ?
// (tx_gain=-1000 does not work - it still sets tx_gain to min.possible value 14)
name: "sdr",
// _UCELL1_ru 2T1R (sdr)
// _UCELL2_ru 2T2R (sdr)
// __UCELL1__ru 2T1R (sdr)
// __UCELL2__ru 2T2R (sdr)
args: "dev0=/dev/sdr0,dev1=/dev/sdr2",
rx_antenna:"tx_rx",
tdd_tx_mod: 1,
......
{%- import 'slaplte.jinja2' as slaplte with context %}
{%- set B = slaplte.B %}
{%- set J = slaplte.J %}
{%- set jcell_ru_ref = slaplte.jcell_ru_ref %}
......@@ -39,7 +40,7 @@
{%- set iru = iru_dict[ru_ref] %}
{%- set ru = iru['_'] %}
// {{ cell_ref }}
// {{ B(cell_ref) }}
{
rf_port: {{ ru._rf_port }},
n_antenna_dl: {{ ru.n_antenna_dl }},
......@@ -69,7 +70,7 @@
{%- set ru_ref = J(jcell_ru_ref(icell)) %}
{%- set iru = iru_dict[ru_ref] %}
{%- set ru = iru['_'] %}
// {{ cell_ref }}
// {{ B(cell_ref) }}
{
rf_port: {{ ru._rf_port }},
n_antenna_dl: {{ ru.n_antenna_dl }},
......@@ -91,7 +92,7 @@
ue_list: [
{%- for ue_ref, iue in iue_dict|dictsort %}
{%- set ue = iue['_'] %}
// {{ ue_ref }}
// {{ B(ue_ref) }}
{
sim_algo: "{{ ue.sim_algo }}",
opc: "{{ ue.opc }}",
......
......@@ -189,6 +189,7 @@ context =
key slapparameter_dict slap-configuration:configuration
key gtp_addr_v6 slap-configuration:ipv6-random
raw gtp_addr_v4 {{ lan_ipv4 }}
import xbuildout xbuildout
import netaddr netaddr
${:extra-context}
......@@ -200,14 +201,18 @@ url = ${enb-config-dl:target}
url = {{ enb_template }}
{% endif %}
output = ${directory:etc}/enb.cfg
extra-context =
json iru_dict {{ rulib.iru_dict | tojson }}
json icell_dict {{ rulib.icell_dict | tojson }}
json ipeer_dict {{ ipeer_dict | tojson }}
json ipeercell_dict {{ ipeercell_dict | tojson }}
import json_module json
import-list =
rawfile slaplte.jinja2 {{ slaplte_template }}
extra-context =
import json_module json
key iru_dict :iru_dict
key icell_dict :icell_dict
key ipeer_dict :ipeer_dict
key ipeercell_dict :ipeercell_dict
iru_dict = {{ dumps(rulib.iru_dict) }}
icell_dict = {{ dumps(rulib.icell_dict) }}
ipeer_dict = {{ dumps(ipeer_dict) }}
ipeercell_dict = {{ dumps(ipeercell_dict) }}
[publish-connection-information]
......@@ -221,8 +226,8 @@ enb-ipv4 = {{ lan_ipv4 }}
amarisoft-version = {{ lte_version }}
license-expiration = {{ lte_expiration }}
monitor-gadget-url = ${:monitor-base-url}/gadget/software.cfg.html
ru-list = {{ rulib.iru_dict.keys() | sort | join(', ') }}
cell-list = {{ rulib.icell_dict.keys() | sort | join(', ') }}
ru-list = {{ dumps(rulib.iru_dict.keys() | sort) }}
cell-list = {{ dumps(rulib.icell_dict.keys() | sort) }}
# TODO peer-list peer-cell-list
peer-list = XXX
peer-cell-list = XXX
......
......@@ -107,6 +107,7 @@ context =
section slap_configuration slap-configuration
section pub_info publish-connection-information
key slapparameter_dict slap-configuration:configuration
import xbuildout xbuildout
${:extra-context}
[lte-ue-config]
......@@ -117,13 +118,16 @@ url = ${ue-config-dl:target}
url = {{ ue_template }}
{% endif %}
output = ${directory:etc}/ue.cfg
extra-context =
json iru_dict {{ rulib.iru_dict | tojson }}
json icell_dict {{ rulib.icell_dict | tojson }}
json iue_dict {{ iue_dict | tojson }}
import json_module json
import-list =
rawfile slaplte.jinja2 {{ slaplte_template }}
extra-context =
import json_module json
key iru_dict :iru_dict
key icell_dict :icell_dict
key iue_dict :iue_dict
iru_dict = {{ dumps(rulib.iru_dict) }}
icell_dict = {{ dumps(rulib.icell_dict) }}
iue_dict = {{ dumps(iue_dict) }}
[publish-connection-information]
......
......@@ -27,6 +27,7 @@ sys.path[0:0] = [
'/srv/slapgrid/slappart91/srv/project/slapos',
'/srv/slapgrid/slappart91/srv/project/slapos/software/ors-amarisoft/test',
'/srv/slapgrid/slappart91/srv/runner/software/45a1e838784afb18daf420009d925c78/eggs/xmltodict-0.13.0-py3.9.egg',
'/srv/slapgrid/slappart91/srv/runner/software/45a1e838784afb18daf420009d925c78/eggs/pcpp-1.30-py3.9.egg',
'/srv/slapgrid/slappart91/srv/runner/software/45a1e838784afb18daf420009d925c78/eggs/requests-2.31.0-py3.9.egg',
'/srv/slapgrid/slappart91/srv/runner/software/45a1e838784afb18daf420009d925c78/eggs/testfixtures-6.11.0-py3.9.egg',
......
......@@ -81,6 +81,19 @@ RU2['mac_addr'] = '90:A9:F7:C0:00:03'
iru1 = iENB(eref('RU1'), RU1)
iru2 = iENB(eref('RU2'), RU2)
# XXX to test wrt buildout code injection
if 0:
RU3 = {
'ru_type': 'sdr',
'ru_link_type': 'sdr',
'sdr_dev_list': [0, 1],
'n_antenna_dl': 4,
'n_antenna_ul': 2,
'tx_gain': 51,
'rx_gain': 52,
}
iENB(eref('RU3\nzzz ${aaa:bbb}\nccc'), RU3)
# Cells
CELL1 = {
......
......@@ -108,6 +108,18 @@
"default": 0
}
}
},
"mac_addr": {
"title": "RU MAC address",
"description": "RU MAC address used for NETCONF",
"type": "string",
"options": {
"dependencies": {
"ru_link_type": "cpri"
}
}
}
}
......
......@@ -41,7 +41,7 @@
{%- set pretty_name = name.removeprefix('%s.' % root) %}
{{ part('promise-'+name) }}
<= monitor-promise-base
name = {{ pretty_name }}.py
name = {{ dumps('%s.py' % pretty_name) }}
config-testing = {{ testing }}
config-stats-period = {{ slapparameter_dict.get("enb_stats_fetch_period", 60) }}
{%- endmacro %}
......@@ -153,7 +153,8 @@ context =
import netaddr netaddr
section directory directory
section vtap_jdict vtap_jdict
json iru_dict {{ iru_dict | tojson }}
key iru_dict :iru_dict
iru_dict = {{ dumps(iru_dict) }}
{{ part('dnsmasq-service') }}
recipe = slapos.cookbook:wrapper
......@@ -185,7 +186,7 @@ hash-files =
{%- endif %}
{%- endfor %}
# {{ ru_ref }} {{ ru.n_antenna_dl }}T{{ ru.n_antenna_ul }}R ({{ ru.ru_type }})
# {{ dumps(ru_ref) }} {{ ru.n_antenna_dl }}T{{ ru.n_antenna_ul }}R ({{ ru.ru_type }})
{%- if ru.ru_link_type == 'sdr' %}
{%- for (i, n) in enumerate(ru.sdr_dev_list) %}
{{ promise('%s-sdr-busy%s' % (ru_ref, '-%d' % (i+1) if i > 0 else '')) }}
......@@ -229,13 +230,13 @@ config-max-rx-sample-db = {{ slapparameter_dict.get("max_rx_sample_db", 0) }}
{#- publish information about RU #}
{{ part('publish-%s' % ru_ref) }}
recipe = slapos.cookbook:publish.serialised
-slave-reference = {{ iru.slave_reference }}
enb = {{ root }}
-slave-reference = {{ dumps(iru.slave_reference) }}
{{ slap_configuration['slap-software-type'] }} = {{ dumps(root) }}
{%- set iru_icell_ref_list = [] %}
{%- for icell in iru_icell_list %}
{%- do iru_icell_ref_list.append(J(jref_of_shared(icell))) %}
{%- endfor %}
cell-list = {{ iru_icell_ref_list | join(', ') }}
cell-list = {{ dumps(iru_icell_ref_list) }}
{%- if ru.ru_link_type == 'cpri' %}
ipv6 = ${vtap.{{ ru.cpri_link._tap }}:gateway}
{%- endif %}
......@@ -255,31 +256,38 @@ ipv6 = ${vtap.{{ ru.cpri_link._tap }}:gateway}
{{ part('drb-config-%s' % cell_ref) }}
<= config-base
url = {{ {'lte': drb_lte_template, 'nr': drb_nr_template} [cell.cell_type] }}
output = ${directory:etc}/{{cell_ref}}-drb.cfg
output = ${directory:etc}/{{B('%s-drb.cfg' % cell_ref)}}
extra-context =
json cell_ref {{ cell_ref | tojson }}
json cell {{ cell | tojson }}
json ru_ref {{ ru_ref | tojson }}
json ru {{ ru | tojson }}
key cell_ref :cell_ref
key cell :cell
key ru_ref :ru_ref
key ru :ru
cell_ref = {{ dumps(cell_ref) }}
cell = {{ dumps(cell ) }}
ru_ref = {{ dumps(ru_ref ) }}
ru = {{ dumps(ru ) }}
{{ part('sib23-config-%s' % cell_ref) }}
<= config-base
url = {{ sib23_template }}
output = ${directory:etc}/{{cell_ref}}-sib23.asn
output = ${directory:etc}/{{B('%s-sib23.asn' % cell_ref)}}
extra-context =
json cell_ref {{ cell_ref | tojson }}
json cell {{ cell | tojson }}
json ru_ref {{ ru_ref | tojson }}
json ru {{ ru | tojson }}
key cell_ref :cell_ref
key cell :cell
key ru_ref :ru_ref
key ru :ru
cell_ref = {{ dumps(cell_ref) }}
cell = {{ dumps(cell ) }}
ru_ref = {{ dumps(ru_ref ) }}
ru = {{ dumps(ru ) }}
{%- endif %}
{#- publish information about the cell #}
{{ part('publish-%s' % cell_ref) }}
recipe = slapos.cookbook:publish.serialised
-slave-reference = {{ icell.slave_reference }}
enb = {{ root }}
ru = {{ ru_ref }}
# XXX enb -> ue in case of uesim
-slave-reference = {{ dumps(icell.slave_reference) }}
{{ slap_configuration['slap-software-type'] }} = {{ dumps(root) }}
ru = {{ dumps(ru_ref) }}
# XXX +error
{%- endfor %}
......@@ -321,7 +329,8 @@ context =
raw stats_period {{ slapparameter_dict.get("enb_stats_fetch_period", 60) }}
raw testing {{ testing }}
raw python_path {{ buildout_directory}}/bin/pythonwitheggs
json iru_dict {{ iru_dict | tojson }}
key iru_dict :iru_dict
iru_dict = {{ dumps(iru_dict) }}
mode = 0775
url = {{ ru_amarisoft_stats_template }}
output = ${directory:bin}/amarisoft-stats.py
......
......@@ -124,6 +124,7 @@
<downlink-radio-frame-offset>0</downlink-radio-frame-offset>
<downlink-sfn-offset>0</downlink-sfn-offset>
<!-- <gain>{{ ru.rx_gain }}</gain> -->
<!-- TODO(lu.xu): clarify with Lopcomm regaring rx gain -->
<gain-correction>0.0</gain-correction>
<n-ta-offset>0</n-ta-offset>
</rx-array-carriers>
......
......@@ -12,6 +12,7 @@
"tx_gain",
"rx_gain",
"cpri_link",
"mac_addr"
],
......@@ -50,11 +51,6 @@
}
},
"mac_addr": {
"title": "RU MAC address",
"description": "RU MAC address used for NETCONF",
"type": "string"
},
"reset_schedule": {
"title": "Cron schedule for RRH reset",
"description": "Refer https://crontab.guru/ to make a reset schedule for RRH, for example, '0 1 * * *' means the RRH will reset every day at 1 am",
......
......@@ -23,11 +23,11 @@ config-port = 830
[{{ B('%s-software-template' % ru_ref) }}]
recipe = slapos.recipe.template:jinja2
extensions = jinja2.ext.do
_logbase = ${directory:var}/log/{{ru_ref}}-software
_logbase = ${directory:var}/log/{{B('%s-software' % ru_ref)}}
log-output = ${:_logbase}.log
software-reply-json-log-output = ${:_logbase}-reply.json.log
remote-file-path = sftp://${user-info:pw-name}@[${sshd-service:ipv6}]:${sshd-service:port}{{ru_lopcomm_firmware_path}}
is_firmware_updated = ${directory:etc}/{{ru_ref}}.is_firmware_updated
is_firmware_updated = ${directory:etc}/{{B('%s.is_firmware_updated' % ru_ref)}}
context =
section directory directory
section vtap vtap.{{ ru.cpri_link._tap }}
......@@ -43,7 +43,7 @@ context =
import netaddr netaddr
mode = 0775
url = {{ ru_lopcomm_software_template }}
output = ${directory:script}/{{ru_ref}}-software.py
output = ${directory:script}/{{B('%s-software.py' % ru_ref)}}
{{ promise('%s-firmware' % ru_ref) }}
promise = check_command_execute
......@@ -67,17 +67,19 @@ url = ${ {{-B('%s-cu-config-dl' % ru_ref)}}:target}
{% else %}
url = {{ ru_lopcomm_cu_config_template }}
{% endif %}
output = ${directory:etc}/{{ru_ref}}-cu_config.xml
output = ${directory:etc}/{{B('%s-cu_config.xml' % ru_ref)}}
extra-context =
import xearfcn_module xlte.earfcn
import xnrarfcn_module xlte.nrarfcn
json ru {{ ru | tojson }}
json cell {{ cell | tojson }}
key ru :ru
key cell :cell
ru = {{ dumps(ru) }}
cell = {{ dumps(cell) }}
[{{ B('%s-config-template' % ru_ref) }}]
recipe = slapos.recipe.template:jinja2
extensions = jinja2.ext.do
log-output = ${directory:var}/log/{{ru_ref}}-config.log
log-output = ${directory:var}/log/{{B('%s-config.log' % ru_ref)}}
context =
section directory directory
section vtap vtap.{{ ru.cpri_link._tap }}
......@@ -90,7 +92,7 @@ context =
import netaddr netaddr
mode = 0775
url = {{ ru_lopcomm_config_template }}
output = ${directory:script}/{{ru_ref}}-config.py
output = ${directory:script}/{{B('%s-config.py' % ru_ref)}}
{{ promise('%s-config-log' % ru_ref) }}
promise = check_lopcomm_config_log
......@@ -102,7 +104,7 @@ config-config-log = ${ {{-B('%s-config-template' % ru_ref)}}:log-output}
[{{ B('%s-stats-template' % ru_ref) }}]
recipe = slapos.recipe.template:jinja2
extensions = jinja2.ext.do
_logbase = ${directory:var}/log/{{ru_ref}}
_logbase = ${directory:var}/log/{{B('%s' % ru_ref)}}
log-output = ${:_logbase}-stats.log
json-log-output = ${:_logbase}-stats.json.log
cfg-json-log-output = ${:_logbase}-config.json.log
......@@ -110,7 +112,7 @@ supervision-json-log-output = ${:_logbase}-supervision.json.log
ncsession-json-log-output = ${:_logbase}-ncsession.json.log
software-json-log-output = ${:_logbase}-software.json.log
supervision-reply-json-log-output = ${:_logbase}-supervision-reply.json.log
is_netconf_connected = ${directory:etc}/{{ru_ref}}.is_netconf_connected
is_netconf_connected = ${directory:etc}/{{B('%s.is_netconf_connected' % ru_ref)}}
context =
section directory directory
section vtap vtap.{{ ru.cpri_link._tap }}
......@@ -129,12 +131,12 @@ context =
import netaddr netaddr
mode = 0775
url = {{ ru_lopcomm_stats_template }}
output = ${directory:bin}/{{ru_ref}}-stats.py
output = ${directory:bin}/{{B('%s-stats.py' % ru_ref)}}
{{ part('%s-stats-service' % ru_ref) }}
recipe = slapos.cookbook:wrapper
command-line = ${ {{-B('%s-stats-template' % ru_ref)}}:output}
wrapper-path = ${directory:service}/{{ru_ref}}-stats
wrapper-path = ${directory:service}/{{B('%s-stats' % ru_ref)}}
mode = 0775
hash-files =
${:command-line}
......@@ -179,7 +181,7 @@ config-stats-log = ${ {{-B('%s-stats-template' % ru_ref)}}:log-output}
[{{ B('%s-reset-info-template' % ru_ref) }}]
recipe = slapos.recipe.template:jinja2
extensions = jinja2.ext.do
_logbase = ${directory:var}/log/{{ru_ref}}-reset-info
_logbase = ${directory:var}/log/{{B('%s-reset-info' % ru_ref)}}
log-output = ${:_logbase}.log
json-log-output = ${:_logbase}.json.log
context =
......@@ -191,12 +193,12 @@ context =
import netaddr netaddr
mode = 0775
url = {{ ru_lopcomm_reset_info_template }}
output = ${directory:bin}/{{ru_ref}}-reset-info.py
output = ${directory:bin}/{{B('%s-reset-info.py' % ru_ref)}}
[{{ B('%s-reset-template' % ru_ref) }}]
recipe = slapos.recipe.template:jinja2
extensions = jinja2.ext.do
_logbase = ${directory:var}/log/{{ru_ref}}-reset
_logbase = ${directory:var}/log/{{B('%s-reset' % ru_ref)}}
log-output = ${:_logbase}.log
json-log-output = ${:_logbase}.json.log
context =
......@@ -207,19 +209,19 @@ context =
import netaddr netaddr
mode = 0775
url = {{ ru_lopcomm_reset_template }}
output = ${directory:etc}/{{ru_ref}}-reset.py
output = ${directory:etc}/{{B('%s-reset.py' % ru_ref)}}
{{ part('%s-reset-cron' % ru_ref) }}
recipe = slapos.cookbook:cron.d
cron-entries = ${cron:cron-entries}
name = {{ru_ref}}-reset
name = {{B('%s-reset' % ru_ref)}}
frequency = {{ ru.reset_schedule }}
command = {{ buildout_directory}}/bin/pythonwitheggs ${ {{-B('%s-reset-template' % ru_ref)}}:output}
{{ part('%s-reset-info-service' % ru_ref) }}
recipe = slapos.cookbook:wrapper
command-line = ${ {{- ru_ref}}-reset-info-template:output}
wrapper-path = ${directory:service}/{{ru_ref}}-reset-info
command-line = ${ {{-B('%s-reset-info-template' % ru_ref)}}:output}
wrapper-path = ${directory:service}/{{B('%s-reset-info' % ru_ref)}}
mode = 0775
hash-files =
${:command-line}
......
......@@ -10,7 +10,10 @@
"n_antenna_dl",
"n_antenna_ul",
"tx_gain",
"rx_gain"
"rx_gain",
"cpri_link",
"mac_addr"
],
"properties": {
......
# Copyright (C) 2023 Nexedi SA and Contributors.
# Copyright (C) 2023-2024 Nexedi SA and Contributors.
#
# This program is free software: you can Use, Study, Modify and Redistribute
# it under the terms of the GNU General Public License version 3, or (at your
......@@ -19,7 +19,6 @@
- encode/decode convert string to/from form, that is suitable to be used in
names of buildout sections.
- XXX quote
"""
......@@ -60,6 +59,13 @@
#
# # referring to <ru_ref>-stats
# ${ {{-B('%s-stats' % ru_ref)}}:output}
#
#
# See also `dumps` in buildout for a way to serialize option values with
# protection against code injection:
#
# https://lab.nexedi.com/nexedi/slapos.buildout/commit/4e13dcb9
# https://lab.nexedi.com/nexedi/slapos.recipe.template/commit/84dc7957
def encode(s: str) -> str:
s = s.encode('utf-8')
outv = []
......@@ -128,18 +134,6 @@ def _decode(s):
return out
# quote converts string s into quoted form with all buildout control characters escaped... XXX
# XXX -> pyquote?
def quote(s: str) -> str:
assert isinstance(s, str), type(s)
r = str.__repr__(s) # both str and markupsafe.Markup go as regular str
for c in '$[]\n':
r = r.replace(c, r'\x%02x' % ord(c))
if r[1:-1] == s:
return s # original string
return '!py!' + r
# ----------------------------------------
import re
......@@ -198,8 +192,3 @@ def test_encode():
def _(cause):
assert isinstance(cause, UnicodeDecodeError)
checkbad(x, _)
def test_quote():
# XXX
pass
......@@ -79,6 +79,10 @@
}
%}
{#- XXX explain #}
{%- set B = xbuildout.encode %}
{#- J is used around macro calls to retrieve returned objects.
It is needed to workaround jinja2 limitation that macro can return only
......@@ -419,7 +423,7 @@
{%- set rx_gainv = [] %} {#- rx_gain by rx channel #}
{%- for (ru_ref, iru) in iru_dict.items() | sort(attribute="1._._rf_port") %}
{%- set ru = iru['_'] %}
// {{ ru_ref }} {{ ru.n_antenna_dl }}T{{ ru.n_antenna_ul }}R ({{ ru.ru_type }})
// {{ B(ru_ref) }} {{ ru.n_antenna_dl }}T{{ ru.n_antenna_ul }}R ({{ ru.ru_type }})
{%- if ru.ru_type == 'sdr' %}
{%- do ru_sdr_dict.update({len(dev_argv): ru}) %}
{%- for n in ru.sdr_dev_list %}
......
......@@ -6,7 +6,12 @@
import zc.buildout.buildout # XXX workaround for https://lab.nexedi.com/nexedi/slapos.recipe.template/merge_requests/9
from slapos.recipe.template import jinja2_template
import json, copy, sys, os, pprint, glob
import json, copy, sys, os, pprint, glob, types
sys.path.insert(0, './ru')
import xbuildout
B = xbuildout.encode
# j2render renders config/<src> into config/out/<out> with provided json parameters.
......@@ -19,6 +24,7 @@ def j2render(src, out, jcfg):
textctx = ''
for k, v in ctx.items():
textctx += 'json %s %s\n' % (k, json.dumps(v))
textctx += 'import xbuildout xbuildout\n'
textctx += 'import json_module json\n'
textctx += 'import nrarfcn_module nrarfcn\n'
textctx += 'import xearfcn_module xlte.earfcn\n'
......@@ -466,11 +472,11 @@ def do_enb():
'ru': ru,
})
j2render('drb_%s.jinja2.cfg' % cell['cell_type'],
'%s-drb.cfg' % cell_ref,
B('%s-drb.cfg' % cell_ref),
jctx)
j2render('sib23.jinja2.asn',
'%s-sib23.asn' % cell_ref,
B('%s-sib23.asn' % cell_ref),
jctx)
......
......@@ -46,6 +46,7 @@ setup(
'slapos.libnetworkcache',
'slapos.cookbook',
'pcpp',
'xmltodict',
],
zip_safe=True,
test_suite='test',
......
# Copyright (C) 2023 Nexedi SA and Contributors.
# Copyright (C) 2023-2024 Nexedi SA and Contributors.
#
# This program is free software: you can Use, Study, Modify and Redistribute
# it under the terms of the GNU General Public License version 3, or (at your
......@@ -16,16 +16,38 @@
# See COPYING file for full licensing terms.
# See https://www.nexedi.com/licensing for rationale and options.
# Unit-tests for generic software for Amarisoft 4G/5G stack.
#
# Here we verify only generated configurations because it is not possible to
# run Amarisoft software on testnodes due to licensing restrictions. End-to-end
# testing complements unit-testing by verifying how LTE works for real, but it
# needs dedicated hardware test setup.
#
# Here we test:
#
# - enb (see TestENB_*)
# - uesim (see TestUEsim_*)
#
# Currently there is no tests for core-network, because for core-network
# there is no difference in between generic and ORS modes and core-network is
# already verified by test_ors.
import os
import json
import io
import yaml
import pcpp
import xmltodict
import sys
sys.path.insert(0, '../ru')
import xbuildout
import unittest
from slapos.testing.testcase import makeModuleSetUpAndTestCaseClass
setUpModule, AmariTestCase = makeModuleSetUpAndTestCaseClass(
setUpModule, _AmariTestCase = makeModuleSetUpAndTestCaseClass(
os.path.abspath(
os.path.join(os.path.dirname(__file__), '..', 'software.cfg')))
......@@ -37,7 +59,7 @@ setUpModule, AmariTestCase = makeModuleSetUpAndTestCaseClass(
# - BW indicates specified bandwidth.
# - CENB indicates a ENB-kind cell.
# - CUE indicates an UE-kind cell.
# - TAC indicates specified Traking Area Code.
# - TAC indicates specified Tracking Area Code.
# - LTE_PEER/NR_PEER indicate an LTE/NR ENB-PEER-kind cell.
# - X2_PEER/XN_PEER indicate an LTE/NR ENB peer.
......@@ -73,16 +95,14 @@ def CENB(cell_id, pci):
}
# CUE indicates an UE-kind cell.
def CUE(): ... # XXX
CUE = {'cell_kind': 'ue'}
# TAC returns basic parameters to indicate specified Traking Area Code.
# TAC returns basic parameters to indicate specified Tracking Area Code.
def TAC(tac):
return {
'tac': '0x%x' % tac,
}
CUE = {'cell_kind': 'ue'}
# LTE_PEER/NR_PEER return basic parameters to indicate an LTE/NR ENB-PEER-kind cell.
def LTE_PEER(e_cell_id, pci, tac):
return {
......@@ -112,88 +132,33 @@ def XN_PEER(xn_addr):
'xn_addr': xn_addr,
}
# ----
# --------
# XXX doc
# XXX approach is to test generated enb.cfg
class ENBTestCase(AmariTestCase):
maxDiff = None # want to see full diff in test run log on an error
# AmariTestCase is base class for all tests.
class AmariTestCase(_AmariTestCase):
maxDiff = None # show full diff in test run log on an error
# stress correctness of ru_ref/cell_ref/... usage throughout all places in
# buildout code - special characters should not lead to wrong templates or
# code injection.
default_partition_reference = AmariTestCase.default_partition_reference + \
default_partition_reference = _AmariTestCase.default_partition_reference + \
' ${a:b}\n[c]\n;'
# XXX temp
# faster edit/try cycle when enabled (handy during development)
if 0:
instance_max_retry = 1
report_max_retry = 1
@classmethod
def getInstanceSoftwareType(cls):
return "enb"
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.enb_cfg = yamlpp_load(cls.ipath('etc/enb.cfg'))
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps({
'testing': True,
'enb_id': '0x17',
'gnb_id': '0x23',
'gnb_id_bits': 30,
})}
@classmethod
def requestDefaultInstance(cls, state='started'):
inst = super().requestDefaultInstance(state=state)
cls.requestAllShared(inst)
return inst
# requestAllShared adds all shared instances of the testcase over imain.
# requestAllShared should add all shared instances of the testcase over imain.
@classmethod
def requestAllShared(cls, imain):
def _(subref, ctx):
return cls.requestShared(imain, subref, ctx)
_('PEER4', X2_PEER('44.1.1.1'))
_('PEER5', XN_PEER('55.1.1.1'))
_('PEERCELL4', LTE(700) | LTE_PEER(0x12345, 35, 0x123))
_('PEERCELL5', NR(520000,38) | NR_PEER(0x77712,22, 75, 0x321))
cls.ho_inter = [
dict(rat='eutra', cell_id=0x12345, n_id_cell=35, dl_earfcn= 700, tac=0x123),
dict(rat='nr', nr_cell_id=0x77712, gnb_id_bits=22, n_id_cell=75,
dl_nr_arfcn=520000, ul_nr_arfcn=520000, ssb_nr_arfcn=520090, band=38,
tac = 0x321),
]
# XXX doc 4 RU x 4 CELL (4f,4t,5f,5t) RUcfg
def RU(i):
ru = cls.RUcfg(i)
ru = ru | {'tx_gain': 10+i, 'rx_gain': 20+i, 'txrx_active': 'INACTIVE'}
cls.requestShared(imain, 'RU%d' % i, ru)
def CELL(i, ctx):
cell = {
'ru': {
'ru_type': 'ru_ref',
'ru_ref': cls.ref('RU%d' % i),
}
}
cell.update(CENB(i, 0x10+i))
cell.update({'root_sequence_index': 200+i,
'inactivity_timer': 1000+i})
cell.update(ctx)
cls.requestShared(imain, 'RU%d.CELL' % i, cell)
RU(1); CELL(1, FDD | LTE( 100) | BW( 5) | TAC(0x101))
RU(2); CELL(2, TDD | LTE( 36100) | BW(10) | TAC(0x102))
RU(3); CELL(3, FDD | NR (430100, 1) | BW(15))
RU(4); CELL(4, TDD | NR (510100,41) | BW(20))
raise NotImplementedError
# requestShared requests one shared instance over imain with specified subreference and parameters.
@classmethod
......@@ -222,55 +187,150 @@ class ENBTestCase(AmariTestCase):
assert path[:1] != '/', path
return '%s/%s' % (cls.computer_partition_root_path, path)
# --------
def test_enb_conf_basic(t):
# ---- eNB + base class for similar services that do radio ----
# RFTestCase4 is base class for tests of all services that do radio.
#
# It instantiates a service with several Radio Units and Cells attached:
#
# 4 RU x 4 CELL are requested to verify all {FDD,TDD}·{LTE,NR} combinations.
#
# In requested instances mostly non-overlapping range of numbers are
# assigned to parameters according to the following scheme:
#
# 0+ cell_id
# 0x10+ pci
# 0x100+ tac
# 10+ tx_gain
# 20+ rx_gain
# xxx+i·100 dl_arfcn
# 5,10,15,20 bandwidth
# 100+ root_sequence_index
# 1000+ inactivity_timer
#
# this allows to quickly see offhand to which cell/ru and parameter a
# particular number belongs to.
#
# Subclasses should define:
#
# - RUcfg(i) to return primary parameters specific for i'th RU configuration
# like ru_type - to verify particular RU driver, sdr_dev, sfp_port and so on.
# - CELLcfg(i) to tune parameters of i'th cell, for example cell_kind.
# - .rf_cfg with loaded service config.
class RFTestCase4(AmariTestCase):
@classmethod
def requestAllShared(cls, imain):
def RU(i):
ru = cls.RUcfg(i)
ru |= {'n_antenna_dl': 4, 'n_antenna_ul': 2}
ru |= {'tx_gain': 10+i, 'rx_gain': 20+i, 'txrx_active': 'INACTIVE'}
cls.requestShared(imain, 'RU%d' % i, ru)
def CELL(i, ctx):
cell = {
'ru': {
'ru_type': 'ru_ref',
'ru_ref': cls.ref('RU%d' % i),
}
}
cell |= cls.CELLcfg(i)
cell |= ctx
cls.requestShared(imain, 'RU%d.CELL' % i, cell)
RU(1); CELL(1, FDD | LTE( 100) | BW( 5))
RU(2); CELL(2, TDD | LTE( 40200) | BW(10))
RU(3); CELL(3, FDD | NR (300300,74) | BW(15))
RU(4); CELL(4, TDD | NR (470400,40) | BW(20))
def test_rf_cfg_txrx_gain(t):
# NOTE even though setting tx_gain/rx_gain in enb.cfg does not make any
# difference for CPRI case, we still do set it there for consistency.
# For the reference: for CPRI case the real tx/rx gain is set in
# RU configuration and is verified by RU tests.
t.assertEqual(t.rf_cfg['tx_gain'], [11]*4 + [12]*4 + [13]*4 + [14]*4)
t.assertEqual(t.rf_cfg['rx_gain'], [21]*2 + [22]*2 + [23]*2 + [24]*2)
# ENBTestCase4 provides base class for unit-testing eNB service.
#
# It instantiates enb with 4 Radio Units x 4 Cells and verifies generated
# enb.cfg to match what is expected.
class ENBTestCase4(RFTestCase4):
@classmethod
def getInstanceSoftwareType(cls):
return "enb"
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.enb_cfg = cls.rf_cfg = yamlpp_load(cls.ipath('etc/enb.cfg'))
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps({
'testing': True,
'enb_id': '0x17',
'gnb_id': '0x23',
'gnb_id_bits': 30,
})}
@classmethod
def requestAllShared(cls, imain):
super().requestAllShared(imain)
def _(subref, ctx):
return cls.requestShared(imain, subref, ctx)
_('PEER4', X2_PEER('44.1.1.1'))
_('PEER5', XN_PEER('55.1.1.1'))
_('PEERCELL4', LTE(700) | LTE_PEER(0x12345, 35, 0x123))
_('PEERCELL5', NR(520000,38) | NR_PEER(0x77712,22, 75, 0x321))
cls.ho_inter = [
dict(rat='eutra', cell_id=0x12345, n_id_cell=35, dl_earfcn= 700, tac=0x123),
dict(rat='nr', nr_cell_id=0x77712, gnb_id_bits=22, n_id_cell=75,
dl_nr_arfcn=520000, ul_nr_arfcn=520000, ssb_nr_arfcn=520090, band=38,
tac = 0x321),
]
def CELLcfg(i):
return CENB(i, 0x10+i) | TAC(0x100+i) | {
'root_sequence_index': 100+i,
'inactivity_timer': 1000+i}
# basic enb parameters
def test_enb_cfg_basic(t):
assertMatch(t, t.enb_cfg, dict(
enb_id=0x17, gnb_id=0x23, gnb_id_bits=30,
x2_peers=['44.1.1.1'], xn_peers=['55.1.1.1'],
))
# XXX kill
"""
# HO(inter)
for cell in t.enb_cfg['cell_list'] + t.enb_cfg['nr_cell_list']:
have = {
'cell_id': cell['cell_id'],
'ncell_list_tail': cell['ncell_list'] [-len(t.ho_inter):]
}
want = {
'cell_id': cell['cell_id'],
'ncell_list_tail': t.ho_inter
}
assertMatch(t, have, want)
"""
# basic cell parameters
def test_enb_conf_cell(t):
def test_enb_cfg_cell(t):
assertMatch(t, t.enb_cfg['cell_list'], [
dict( # CELL1
uldl_config=NO, rf_port=0, n_antenna_dl=4, n_antenna_ul=2,
dl_earfcn=100, ul_earfcn=18100,
n_rb_dl=25,
cell_id=0x1, n_id_cell=0x11, tac=0x101,
root_sequence_index=201, inactivity_timer=1001,
root_sequence_index=101, inactivity_timer=1001,
),
dict( # CELL2
uldl_config=2, rf_port=1, n_antenna_dl=4, n_antenna_ul=2,
dl_earfcn=36100, ul_earfcn=36100,
dl_earfcn=40200, ul_earfcn=40200,
n_rb_dl=50,
cell_id=0x2, n_id_cell=0x12, tac=0x102,
root_sequence_index=202, inactivity_timer=1002,
root_sequence_index=102, inactivity_timer=1002,
),
])
assertMatch(t, t.enb_cfg['nr_cell_list'], [
dict( # CELL3
tdd_ul_dl_config=NO, rf_port=2, n_antenna_dl=4, n_antenna_ul=2,
dl_nr_arfcn=430100, ul_nr_arfcn=392100, ssb_nr_arfcn=429890, band=1,
dl_nr_arfcn=300300, ul_nr_arfcn=290700, ssb_nr_arfcn=300270, band=74,
bandwidth=15,
cell_id=0x3, n_id_cell=0x13, tac=NO,
root_sequence_index=203, inactivity_timer=1003,
root_sequence_index=103, inactivity_timer=1003,
),
dict( # CELL4
......@@ -278,52 +338,52 @@ class ENBTestCase(AmariTestCase):
period=5, dl_slots=7, dl_symbols=6, ul_slots=2, ul_symbols=4,
)},
rf_port=3, n_antenna_dl=4, n_antenna_ul=2,
dl_nr_arfcn=510100, ul_nr_arfcn=510100, ssb_nr_arfcn=510010, band=41,
dl_nr_arfcn=470400, ul_nr_arfcn=470400, ssb_nr_arfcn=470430, band=40,
bandwidth=20,
cell_id=0x4, n_id_cell=0x14, tac=NO,
root_sequence_index=204, inactivity_timer=1004,
root_sequence_index=104, inactivity_timer=1004,
),
])
# Carrier Aggregation
def test_enb_conf_ca(t):
def test_enb_cfg_ca(t):
assertMatch(t, t.enb_cfg['cell_list'], [
{ # CELL1
'scell_list': [{'cell_id': 0x2}], # LTE + LTE
'en_dc_scg_cell_list': [{'cell_id': 0x3}, {'cell_id': 0x4}], # LTE + NR
'scell_list': [{'cell_id': 2}], # LTE + LTE
'en_dc_scg_cell_list': [{'cell_id': 3}, {'cell_id': 4}], # LTE + NR
},
{ # CELL2
'scell_list': [{'cell_id': 0x1}], # LTE + LTE
'en_dc_scg_cell_list': [{'cell_id': 0x3}, {'cell_id': 0x4}], # LTE + NR
'scell_list': [{'cell_id': 1}], # LTE + LTE
'en_dc_scg_cell_list': [{'cell_id': 3}, {'cell_id': 4}], # LTE + NR
},
])
assertMatch(t, t.enb_cfg['nr_cell_list'], [
{ # CELL3
'scell_list': [{'cell_id': 0x4}], # NR + NR
'scell_list': [{'cell_id': 4}], # NR + NR
},
{ # CELL4
'scell_list': [{'cell_id': 0x3}], # NR + NR
'scell_list': [{'cell_id': 3}], # NR + NR
},
])
# Handover
def test_enb_conf_ho(t):
def test_enb_cfg_ho(t):
assertMatch(t, t.enb_cfg['cell_list'], [
{ # CELL1
'ncell_list': [
dict(rat='eutra', cell_id= 0x1702, n_id_cell=0x12, dl_earfcn=36100, tac=0x102), # CELL2
dict(rat='nr', cell_id= 0x03), # CELL3
dict(rat='nr', cell_id= 0x04), # CELL4
dict(rat='eutra', cell_id= 0x1702, n_id_cell=0x12, dl_earfcn=40200, tac=0x102), # CELL2
dict(rat='nr', cell_id= 3), # CELL3
dict(rat='nr', cell_id= 4), # CELL4
] + t.ho_inter,
},
{ # CELL2
'ncell_list': [
dict(rat='eutra', cell_id= 0x1701, n_id_cell=0x11, dl_earfcn= 100, tac=0x101), # CELL1
dict(rat='nr', cell_id= 0x03), # CELL3
dict(rat='nr', cell_id= 0x04), # CELL4
dict(rat='nr', cell_id= 3), # CELL3
dict(rat='nr', cell_id= 4), # CELL4
] + t.ho_inter,
},
])
......@@ -331,46 +391,47 @@ class ENBTestCase(AmariTestCase):
{ # CELL3
'ncell_list': [
dict(rat='eutra', cell_id= 0x1701, n_id_cell=0x11, dl_earfcn= 100, tac=0x101), # CELL1
dict(rat='eutra', cell_id= 0x1702, n_id_cell=0x12, dl_earfcn=36100, tac=0x102), # CELL2
dict(rat='nr', cell_id= 0x04), # CELL4
dict(rat='eutra', cell_id= 0x1702, n_id_cell=0x12, dl_earfcn=40200, tac=0x102), # CELL2
dict(rat='nr', cell_id= 4), # CELL4
] + t.ho_inter,
},
{ # CELL4
'ncell_list': [
dict(rat='eutra', cell_id= 0x1701, n_id_cell=0x11, dl_earfcn= 100, tac=0x101), # CELL1
dict(rat='eutra', cell_id= 0x1702, n_id_cell=0x12, dl_earfcn=36100, tac=0x102), # CELL2
dict(rat='nr', cell_id= 0x03), # CELL3
dict(rat='eutra', cell_id= 0x1702, n_id_cell=0x12, dl_earfcn=40200, tac=0x102), # CELL2
dict(rat='nr', cell_id= 3), # CELL3
] + t.ho_inter,
},
])
# XXX SDR driver in all modes
class TestENB_SDR(ENBTestCase):
# ---- RU mixins to be used with RFTestCase4 ----
# SDR4 is mixin to verify SDR driver wrt all LTE/NR x FDD/TDD modes.
class SDR4:
@classmethod
def RUcfg(cls, i):
return {
'ru_type': 'sdr',
'ru_link_type': 'sdr',
'sdr_dev_list': [2*i,2*i+1],
'n_antenna_dl': 4,
'n_antenna_ul': 2,
}
# radio units configuration
def test_enb_conf_ru(t):
rf_driver = t.enb_cfg['rf_driver']
t.assertEqual(rf_driver['args'],
'dev0=/dev/sdr2,dev1=/dev/sdr3,dev2=/dev/sdr4,dev3=/dev/sdr5,' +
'dev4=/dev/sdr6,dev5=/dev/sdr7,dev6=/dev/sdr8,dev7=/dev/sdr9')
# XXX -> generic ? XXX no (for cpri case it is all 0 here)
t.assertEqual(t.enb_cfg['tx_gain'], [11]*4 + [12]*4 + [13]*4 + [14]*4)
t.assertEqual(t.enb_cfg['rx_gain'], [21]*2 + [22]*2 + [23]*2 + [24]*2)
def test_rf_cfg_ru(t):
assertMatch(t, t.rf_cfg['rf_driver'], dict(
args='dev0=/dev/sdr2,dev1=/dev/sdr3,dev2=/dev/sdr4,dev3=/dev/sdr5,' +
'dev4=/dev/sdr6,dev5=/dev/sdr7,dev6=/dev/sdr8,dev7=/dev/sdr9',
cpri_mapping=NO,
cpri_mult=NO,
cpri_rx_delay=NO,
cpri_tx_delay=NO,
cpri_tx_dbm=NO,
))
# TestENB_Lopcomm verifies enb wrt Lopcomm driver in all LTE/NR x FDD/TDD modes
class TestENB_Lopcomm(ENBTestCase):
# Lopcomm4 is mixin to verify Lopcomm driver wrt all LTE/NR x FDD/TDD modes.
class Lopcomm4:
@classmethod
def RUcfg(cls, i):
return {
......@@ -388,177 +449,263 @@ class TestENB_Lopcomm(ENBTestCase):
'mac_addr': '00:0A:45:00:00:%02x' % i,
}
# XXX verify cu_cfg
# radio units configuration in enb.cfg
def test_rf_cfg_ru(t):
assertMatch(t, t.rf_cfg['rf_driver'], dict(
args='dev0=/dev/sdr0@1,dev1=/dev/sdr0@2,dev2=/dev/sdr0@3,dev3=/dev/sdr0@4',
cpri_mapping='hw,hw,hw,hw',
cpri_mult='4,4,4,4',
cpri_rx_delay='41,42,43,44',
cpri_tx_delay='51,52,53,54',
cpri_tx_dbm='61,62,63,64',
))
# RU configuration in cu_config.xml
def test_ru_cu_config_xml(t):
def uctx(rf_mode, cell_type, dl_arfcn, ul_arfcn, bw, dl_freq, ul_freq, tx_gain, rx_gain):
return {
'tx-array-carriers': {
'rw-duplex-scheme': rf_mode,
'rw-type': cell_type,
'absolute-frequency-center': '%d' % dl_arfcn,
'center-of-channel-bandwidth': '%d' % dl_freq,
'channel-bandwidth': '%d' % bw,
'gain': '%d' % tx_gain,
'active': 'INACTIVE',
},
'rx-array-carriers': {
'absolute-frequency-center': '%d' % ul_arfcn,
'center-of-channel-bandwidth': '%d' % ul_freq,
'channel-bandwidth': '%d' % bw,
# XXX no rx_gain
'active': 'INACTIVE',
},
}
_ = t._test_ru_cu_config_xml
# rf_mode ctype dl_arfcn ul_arfcn bw dl_freq ul_freq txg rxg
_(1, uctx('FDD', 'LTE', 100, 18100, 5000000, 2120000000, 1930000000, 11, 21))
_(2, uctx('TDD', 'LTE', 40200, 40200, 10000000, 2551000000, 2551000000, 12, 22))
_(3, uctx('FDD', 'NR', 300300, 290700, 15000000, 1501500000, 1453500000, 13, 23))
_(4, uctx('TDD', 'NR', 470400, 470400, 20000000, 2352000000, 2352000000, 14, 24))
def _test_ru_cu_config_xml(t, i, uctx):
cu_xml = t.ipath('etc/%s' % xbuildout.encode('%s-cu_config.xml' % t.ref('RU%d' % i)))
with open(cu_xml, 'r') as f:
cu = f.read()
cu = xmltodict.parse(cu)
assertMatch(t, cu, {
'xc:config': {
'user-plane-configuration': {
'tx-endpoints': [
{'name': 'TXA0P00C00', 'e-axcid': {'eaxc-id': '0'}},
{'name': 'TXA0P00C01', 'e-axcid': {'eaxc-id': '1'}},
{'name': 'TXA0P01C00', 'e-axcid': {'eaxc-id': '2'}},
{'name': 'TXA0P01C01', 'e-axcid': {'eaxc-id': '3'}},
],
'tx-links': [
{'name': 'TXA0P00C00', 'tx-endpoint': 'TXA0P00C00'},
{'name': 'TXA0P00C01', 'tx-endpoint': 'TXA0P00C01'},
{'name': 'TXA0P01C00', 'tx-endpoint': 'TXA0P01C00'},
{'name': 'TXA0P01C01', 'tx-endpoint': 'TXA0P01C01'},
],
'rx-endpoints': [
{'name': 'RXA0P00C00', 'e-axcid': {'eaxc-id': '0'}},
{'name': 'PRACH0P00C00', 'e-axcid': {'eaxc-id': '8'}},
{'name': 'RXA0P00C01', 'e-axcid': {'eaxc-id': '1'}},
{'name': 'PRACH0P00C01', 'e-axcid': {'eaxc-id': '24'}},
],
'rx-links': [
{'name': 'RXA0P00C00', 'rx-endpoint': 'RXA0P00C00'},
{'name': 'PRACH0P00C00', 'rx-endpoint': 'PRACH0P00C00'},
{'name': 'RXA0P00C01', 'rx-endpoint': 'RXA0P00C01'},
{'name': 'PRACH0P00C01', 'rx-endpoint': 'PRACH0P00C01'},
],
} | uctx
}
})
# XXX not possible to test Lopcomm nor Sunwave because on "slapos standalone" there is no slaptap.
# XXX -> possible - adjust SR with testing=True workaround
# XXX explain ENB does not support mixing SDR + CPRI
class _TestENB_CPRI(ENBTestCase):
# lo x {4t,4f,5t,5f}
# sw x {4t,4f,5t,5f}
# Sunwave4 is mixin to verify Sunwave driver wrt all LTE/NR x FDD/TDD modes.
class Sunwave4:
@classmethod
def requestAllShared(cls, imain):
super().requestAllShared(imain)
# Lopcomm x {4t,4f,5t,5f}
def LO(i):
def RUcfg(cls, i):
return {
'ru_type': 'lopcomm',
'ru_type': 'sunwave',
'ru_link_type': 'cpri',
'cpri_link': {
'sdr_dev': 0,
'sfp_port': 1 + i,
'mult': 4,
'mapping': 'hw',
'rx_delay': 25,
'tx_delay': 14,
'tx_dbm': 63
'sdr_dev': 1,
'sfp_port': i,
'mult': 5,
'mapping': 'bf1',
'rx_delay': 140+i,
'tx_delay': 150+i,
'tx_dbm': 160+i
},
'mac_addr': '00:0A:45:00:00:%02x' % i,
'tx_gain': -11,
'rx_gain': -12,
'txrx_active': 'INACTIVE',
}
cls.requestShared(imain, 'LO1', LO(1))
#cls.requestShared(imain, 'LO2', LO(2))
#cls.requestShared(imain, 'LO3', LO(3))
#cls.requestShared(imain, 'LO4', LO(4))
def LO_CELL(i, ctx):
cell = {
'ru': {
'ru_type': 'ru_ref',
'ru_ref': cls.ref('LO%d' % i),
'mac_addr': '00:FA:FE:00:00:%02x' % i,
}
}
cell.update(CENB(i, i))
cell.update(ctx)
cls.requestShared(imain, 'LO%d.CELL' % i, cell)
LO_CELL(1, FDD | LTE( 100) | BW(10))
#LO_CELL(2, TDD | LTE( 36100) | BW(10))
#LO_CELL(3, FDD | NR (430100, 1) | BW(10))
#LO_CELL(4, TDD | NR (510100,41) | BW(10))
# XXX + sunwave
def test_enb_conf(self):
super().test_enb_conf()
conf = yamlpp_load('%s/etc/enb.cfg' % self.computer_partition_root_path)
rf_driver = conf['rf_driver']
self.assertEqual(rf_driver['args'],
'dev0=/dev/sdr0@1,dev1=/dev/sdr0@2,dev2=/dev/sdr0@3,dev3=/dev/sdr0@4' + # Lopcomm
'') # XXX Sunwave
self.assertEqual(rf_driver['cpri_mapping'], ','.join(['hw']*4 + ['bf1']*4))
self.assertEqual(rf_driver['cpri_mult'], ','.join([ '4']*4 + ['8']*4))
self.assertEqual(rf_driver['rx_delay'], ','.join(['25']*4 + ['XX']*4))
self.assertEqual(rf_driver['tx_delay'], ','.join(['14']*4 + ['XX']*4))
self.assertEqual(rf_driver['tx_dbm'], ','.join(['63']*4 + ['XX']*4))
self.assertEqual(rf_driver['ifname'], ','.join(['XXXX']*4 + ['YYYY']*4))
# XXX tx_gain / rx_gain
self.assertEqual(len(conf['cell_list']), 2*2)
self.assertEqual(len(conf['nr_cell_list']), 2*2)
# XXX RU
# XXX CELLs
# XXX CA
# radio units configuration in enb.cfg
def test_rf_cfg_ru(t):
assertMatch(t, t.rf_cfg['rf_driver'], dict(
args='dev0=/dev/sdr1@1,dev1=/dev/sdr1@2,dev2=/dev/sdr1@3,dev3=/dev/sdr1@4',
cpri_mapping='bf1,bf1,bf1,bf1',
cpri_mult='5,5,5,5',
cpri_rx_delay='141,142,143,144',
cpri_tx_delay='151,152,153,154',
cpri_tx_dbm='161,162,163,164',
))
# RUMultiType4 is mixin to verify that different RU types can be used at the same time.
class RUMultiType4:
# ENB does not support mixing SDR + CPRI - verify only with CPRI-based units
# see https://support.amarisoft.com/issues/26021 for details
@classmethod
def RUcfg(cls, i):
assert 1 <= i <= 4, i
if i in (1,2):
return Lopcomm4.RUcfg(i)
else:
return Sunwave4.RUcfg(i)
# radio units configuration in enb.cfg
def test_rf_cfg_ru(t):
assertMatch(t, t.rf_cfg['rf_driver'], dict(
args='dev0=/dev/sdr0@1,dev1=/dev/sdr0@2,dev2=/dev/sdr1@3,dev3=/dev/sdr1@4',
cpri_mapping='hw,hw,bf1,bf1',
cpri_mult='4,4,5,5',
cpri_rx_delay='41,42,143,144',
cpri_tx_delay='51,52,153,154',
cpri_tx_dbm='61,62,163,164',
))
# instantiate eNB tests
class TestENB_SDR4 (ENBTestCase4, SDR4): pass
class TestENB_Lopcomm4 (ENBTestCase4, Lopcomm4): pass
class TestENB_Sunwave4 (ENBTestCase4, Sunwave4): pass
class TestENB_RUMultiType4(ENBTestCase4, RUMultiType4): pass
# XXX enb - {sdr,lopcomm,sunwave}·2 - {cell_lte1fdd,2tdd, cell_nr1fdd,2tdd} + peer·2 + peercell·2
# XXX uesim - {sdr,lopcomm,sunwave}·2
# XXX core-network - skip - verified by ors
# ---- UEsim ----
"""
class TestUELTEParameters(ORSTestCase): # XXX adjust
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(param_dict)}
# UEsimTestCase4 provides base class for unit-testing UEsim service.
#
# It is similar to ENBTestCase4 but configures UE cells instead of eNB cells.
class UEsimTestCase4(RFTestCase4):
@classmethod
def getInstanceSoftwareType(cls):
return "ue-lte"
def test_ue_lte_conf(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'ue.cfg'))[0]
with open(conf_file, 'r') as f:
conf = yaml.load(f)
self.assertEqual(conf['cell_groups'][0]['cells'][0]['dl_earfcn'], param_dict['dl_earfcn'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['n_antenna_dl'], param_dict['n_antenna_dl'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['n_antenna_ul'], param_dict['n_antenna_ul'])
self.assertEqual(conf['ue_list'][0]['rue_addr'], param_dict['rue_addr'])
self.assertEqual(conf['ue_list'][0]['imsi'], param_dict['imsi'])
self.assertEqual(conf['ue_list'][0]['K'], param_dict['k'])
self.assertEqual(conf['ue_list'][0]['sim_algo'], param_dict['sim_algo'])
self.assertEqual(conf['ue_list'][0]['opc'], param_dict['opc'])
self.assertEqual(conf['ue_list'][0]['amf'], int(param_dict['amf'], 16))
self.assertEqual(conf['ue_list'][0]['sqn'], param_dict['sqn'])
self.assertEqual(conf['ue_list'][0]['impu'], param_dict['impu'])
self.assertEqual(conf['ue_list'][0]['impi'], param_dict['impi'])
self.assertEqual(conf['tx_gain'], param_dict['tx_gain'])
self.assertEqual(conf['rx_gain'], param_dict['rx_gain'])
1/0 # XXX self.assertEqual(cell['n_rb_dl'], 50)
with open(conf_file, 'r') as f:
for l in f:
if l.startswith('#define N_RB_DL'):
self.assertIn('50', l)
class TestUENRParameters(ORSTestCase): # XXX adjust
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(param_dict)}
return "ue"
@classmethod
def getInstanceSoftwareType(cls):
return "ue-nr"
def test_ue_nr_conf(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'ue.cfg'))[0]
with open(conf_file, 'r') as f:
conf = yaml.load(f)
self.assertEqual(conf['cell_groups'][0]['cells'][0]['ssb_nr_arfcn'], param_dict['ssb_nr_arfcn'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['dl_nr_arfcn'], param_dict['dl_nr_arfcn'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['bandwidth'], '10 MHz')
self.assertEqual(conf['cell_groups'][0]['cells'][0]['band'], param_dict['nr_band'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['n_antenna_dl'], param_dict['n_antenna_dl'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['n_antenna_ul'], param_dict['n_antenna_ul'])
self.assertEqual(conf['ue_list'][0]['rue_addr'], param_dict['rue_addr'])
self.assertEqual(conf['ue_list'][0]['imsi'], param_dict['imsi'])
self.assertEqual(conf['ue_list'][0]['K'], param_dict['k'])
self.assertEqual(conf['ue_list'][0]['sim_algo'], param_dict['sim_algo'])
self.assertEqual(conf['ue_list'][0]['opc'], param_dict['opc'])
self.assertEqual(conf['ue_list'][0]['amf'], int(param_dict['amf'], 16))
self.assertEqual(conf['ue_list'][0]['sqn'], param_dict['sqn'])
self.assertEqual(conf['ue_list'][0]['impu'], param_dict['impu'])
self.assertEqual(conf['ue_list'][0]['impi'], param_dict['impi'])
self.assertEqual(conf['tx_gain'], param_dict['tx_gain'])
self.assertEqual(conf['rx_gain'], param_dict['rx_gain'])
class TestUEMonitorGadgetUrl(ORSTestCase):
def setUpClass(cls):
super().setUpClass()
cls.ue_cfg = cls.rf_cfg = yamlpp_load(cls.ipath('etc/ue.cfg'))
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps({'testing': True})}
return {'_': json.dumps({
'testing': True,
})}
@classmethod
def getInstanceSoftwareType(cls):
return "ue"
def CELLcfg(cls, i):
return CUE
def test_monitor_gadget_url(self):
test_monitor_gadget_url(self)
"""
@classmethod
def requestAllShared(cls, imain):
super().requestAllShared(imain)
def UE(i):
ue = {
'ue_type': ('lte', 'nr') [(i-1) % 2],
'rue_addr': 'host%d' % i,
'sim_algo': ('xor', 'milenage', 'tuak') [i-1],
'imsi': '%015d' % i,
'opc': '%032x' % i,
'amf': '0x%04x' % (0x9000+i),
'sqn': '%012x' % i,
'k': 'FFFF%028x' % i,
'impi': 'impi%d@rapid.space' % i,
}
cls.requestShared(imain, 'UE%d' % i, ue)
UE(1)
UE(2)
UE(3)
# ue parameters
def test_ue_cfg_ue(t):
assertMatch(t, t.ue_cfg['ue_list'], [
dict(
as_release=13, ue_category=13, rue_addr='host1',
sim_algo='xor', amf =0x9001, impi='impi1@rapid.space',
sqn ='000000000001',
imsi='000000000000001',
opc ='00000000000000000000000000000001',
K ='FFFF0000000000000000000000000001',
),
dict(
as_release=15, ue_category='nr', rue_addr='host2',
sim_algo='milenage', amf =0x9002, impi='impi2@rapid.space',
sqn ='000000000002',
imsi='000000000000002',
opc ='00000000000000000000000000000002',
K ='FFFF0000000000000000000000000002',
),
dict(
as_release=13, ue_category=13, rue_addr='host3',
sim_algo='tuak', amf =0x9003, impi='impi3@rapid.space',
sqn ='000000000003',
imsi='000000000000003',
opc ='00000000000000000000000000000003',
K ='FFFF0000000000000000000000000003',
),
])
# cells
def test_ue_cfg_cell(t):
assertMatch(t, t.ue_cfg['cell_groups'], [
dict(
group_type='lte',
cells=[
dict( # CELL1
rf_port=0, n_antenna_dl=4, n_antenna_ul=2,
dl_earfcn=100, ul_earfcn=18100,
bandwidth=5,
),
dict( # CELL2
rf_port=1, n_antenna_dl=4, n_antenna_ul=2,
dl_earfcn=40200, ul_earfcn=40200,
bandwidth=10,
),
]
),
dict(
group_type='nr',
cells=[
dict( # CELL3
rf_port=2, n_antenna_dl=4, n_antenna_ul=2,
dl_nr_arfcn=300300, ul_nr_arfcn=290700, ssb_nr_arfcn=300270, band=74,
bandwidth=15,
),
dict( # CELL4
rf_port=3, n_antenna_dl=4, n_antenna_ul=2,
dl_nr_arfcn=470400, ul_nr_arfcn=470400, ssb_nr_arfcn=470430, band=40,
bandwidth=20,
),
]
)
])
# instantiate UEsim tests
class TestUEsim_SDR4 (UEsimTestCase4, SDR4): pass
class TestUEsim_Lopcomm4 (UEsimTestCase4, Lopcomm4): pass
class TestUEsim_Sunwave4 (UEsimTestCase4, Sunwave4): pass
class TestUEsim_RUMultiType4(UEsimTestCase4, RUMultiType4): pass
# ---- misc ----
......@@ -597,7 +744,6 @@ def _matchCollect(v, vok):
if type(v) is dict:
v_ = {}
for k in vok:
#v_[k] = v.get(k, NO)
v_[k] = _matchCollect(v.get(k, NO), vok[k])
return v_
if type(v) is list:
......@@ -621,5 +767,51 @@ def _matchCollect(v, vok):
assert type(v) is not tuple, v
return v
class TestAssertMatch(unittest.TestCase):
def test_assertMatch(t):
y, n = True, False
testv = [ # [](match, v, vok)
(y, 12, 12),
(n, 12, 13),
(n, 12, '12'),
(y, 'a', 'a'),
(n, 'a', 'ab'),
(y, [], []),
(n, [], [1]),
(y, [1], [1]),
(n, [1,2], [1]),
(y, [1,2], [1,2]),
(n, [1,2], ['a',2]),
(y, {}, {}),
(y, {'a': 1}, {}),
(y, {'a': 1}, {'a': 1}),
(n, {'a': 1}, {'a': 2}),
(n, {'a': 1}, {'a': NO}),
(y, {}, {'a': NO}),
(y, {'b': 2}, {'a': NO}),
(n, {'a': 1, 'b': 2}, {'a': NO}),
(n, {'a': 1, 'b': 2}, {'a': NO, 'b': 2}),
(y, {'a': 1, 'b': 2}, { 'b': 2}),
(y, {'a': [1, 2, {'aa': 33, 'bb': 44}]},
{'a': [1, 2, {'aa': 33, 'cc': NO}]}),
(n, {'a': [1, 2, {'aa': 33, 'bb': 44}]},
{'a': [1, 2, {'aa': 35, 'cc': NO}]}),
]
# XXX test for assertMatch
for mok, v, vok in testv:
with t.subTest(mok=mok, v=v, vok=vok):
if mok:
assertMatch(t, v, vok)
else:
t.assertRaises(t.failureException,
assertMatch, t, v, vok)
# hide base TestCases from unittest discovery so that their test_ methods are
# run only on leaf test classes.
def __dir__():
d = list(sorted(globals().keys()))
abstract = {'AmariTestCase', 'RFTestCase4', 'ENBTestCase4', 'UEsimTestCase4'}
for _ in abstract:
d.remove(_)
return d
......@@ -3,20 +3,29 @@
(cd .. && /usr/bin/python3 ../../update-hash)
export SLAPOS_TEST_DEBUG=1
export SLAPOS_TEST_VERBOSE=1
export SLAPOS_TEST_VERBOSE=0
export SLAPOS_TEST_SKIP_SOFTWARE_CHECK=1
export SLAPOS_TEST_SKIP_SOFTWARE_REBUILD=1
export SLAPOS_TEST_SKIP_SOFTWARE_REBUILD=0
rm -rf snapshot
mkdir snapshot
export SLAPOS_TEST_LOG_DIRECTORY=`pwd`/snapshot
#time ../k/kpython_for_test -m unittest discover -v
time ../k/kpython_for_test -m unittest discover -vf
#time ../k/kpython_for_test -m unittest discover -vf -k TestENBParameters
#time ../k/kpython_for_test -m unittest discover -vf -k NBParameters
#time ../k/kpython_for_test -m unittest discover -vf -k CoreNetwork
#time ../k/kpython_for_test -m unittest discover -vf -k MonitorGadget
#time ../k/kpython_for_test -m unittest discover -vf -k SimCard
#time ../k/kpython_for_test -m unittest discover -vf
#time ../k/kpython_for_test -m unittest discover -vf -k TestENB_CPRI
time ../k/kpython_for_test -m unittest discover -vf -k TestENB_SDR
#time ../k/kpython_for_test -m unittest discover -vf -k TestENB_
#time ../k/kpython_for_test -m unittest discover -vf -k TestENB_SDR
#time ../k/kpython_for_test -m unittest discover -vf -k TestENB_Lopcomm
#time ../k/kpython_for_test -m unittest discover -vf -k TestENB_Sunwave
#time ../k/kpython_for_test -m unittest discover -vf -k TestENB_RUMultiType
#time ../k/kpython_for_test -m unittest discover -vf -k TestUEsim_
#time ../k/kpython_for_test -m unittest discover -vf -k TestUEsim_SDR
#time ../k/kpython_for_test -m unittest discover -vf -k TestUEsim_Lopcomm
#time ../k/kpython_for_test -m unittest discover -vf -k TestUEsim_Sunwave
#time ../k/kpython_for_test -m unittest discover -vf -k TestUEsim_RUMultiType
#time ../k/kpython_for_test -m unittest discover -v -k TestAssert
......@@ -12,8 +12,7 @@
"dl_nr_arfcn",
"bandwidth",
"nr_band",
"ssb_nr_arfcn"
"nr_band"
],
"properties": {
......
......@@ -416,6 +416,7 @@ ptyprocess = 0.6.0
psycopg2 = 2.8.6
paho-mqtt = 1.5.0
pcpp = 1.30
xmltodict = 0.13.0
# Patched eggs
PyPDF2 = 1.26.0+SlapOSPatched001
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment