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: kirr/slapos@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 ...@@ -24,11 +24,11 @@ md5sum = f5c76c3443b75569eb18503dce38e783
[slaplte.jinja2] [slaplte.jinja2]
_update_hash_filename_ = slaplte.jinja2 _update_hash_filename_ = slaplte.jinja2
md5sum = 8c044b28682940fbca62657c16613157 md5sum = fa841e105d78aab36b9ea205a69608fb
[ru_libinstance.jinja2.cfg] [ru_libinstance.jinja2.cfg]
_update_hash_filename_ = ru/libinstance.jinja2.cfg _update_hash_filename_ = ru/libinstance.jinja2.cfg
md5sum = 031805301916a7d17a6a8fb31914cbea md5sum = 4c1e6fbd774042cdd12687fd30635c6b
[ru_sdr_libinstance.jinja2.cfg] [ru_sdr_libinstance.jinja2.cfg]
_update_hash_filename_ = ru/sdr/libinstance.jinja2.cfg _update_hash_filename_ = ru/sdr/libinstance.jinja2.cfg
...@@ -36,7 +36,7 @@ md5sum = b7906ca3a6b17963f78f680fc0842b74 ...@@ -36,7 +36,7 @@ md5sum = b7906ca3a6b17963f78f680fc0842b74
[ru_lopcomm_libinstance.jinja2.cfg] [ru_lopcomm_libinstance.jinja2.cfg]
_update_hash_filename_ = ru/lopcomm/libinstance.jinja2.cfg _update_hash_filename_ = ru/lopcomm/libinstance.jinja2.cfg
md5sum = 409ab889d75ec260aa0e52548463a38f md5sum = 667bf3d0af1ae3e6d740c667957449dc
[ru_sunwave_libinstance.jinja2.cfg] [ru_sunwave_libinstance.jinja2.cfg]
_update_hash_filename_ = ru/sunwave/libinstance.jinja2.cfg _update_hash_filename_ = ru/sunwave/libinstance.jinja2.cfg
...@@ -80,7 +80,7 @@ md5sum = 2b8b57c5771b2a2203c0e7767e629e55 ...@@ -80,7 +80,7 @@ md5sum = 2b8b57c5771b2a2203c0e7767e629e55
[ru_xbuildout.py] [ru_xbuildout.py]
_update_hash_filename_ = ru/xbuildout.py _update_hash_filename_ = ru/xbuildout.py
md5sum = b9aa7356ebccfb1e9d2324106ad88485 md5sum = 2856e18a18eb8f0af090cfd714e1973a
[ru_capdo.c] [ru_capdo.c]
_update_hash_filename_ = ru/capdo.c _update_hash_filename_ = ru/capdo.c
...@@ -88,7 +88,7 @@ md5sum = 52da9fe3a569199e35ad89ae1a44c30e ...@@ -88,7 +88,7 @@ md5sum = 52da9fe3a569199e35ad89ae1a44c30e
[template-enb] [template-enb]
_update_hash_filename_ = instance-enb.jinja2.cfg _update_hash_filename_ = instance-enb.jinja2.cfg
md5sum = 143f9b0e9866d37e6527e89f74b4ef1c md5sum = 29b5a5a61b0498681d480726be9e56bf
[template-ors-enb] [template-ors-enb]
_update_hash_filename_ = instance-ors-enb.jinja2.cfg _update_hash_filename_ = instance-ors-enb.jinja2.cfg
...@@ -100,7 +100,7 @@ md5sum = c807be73b9304f5a4c7483a3776bbc17 ...@@ -100,7 +100,7 @@ md5sum = c807be73b9304f5a4c7483a3776bbc17
[template-ue] [template-ue]
_update_hash_filename_ = instance-ue.jinja2.cfg _update_hash_filename_ = instance-ue.jinja2.cfg
md5sum = aa6b8e50bd8d9c4cc6e23b01a2be5644 md5sum = be16ae9b38dd4e46c09bc9eb4bb7eb93
[template-obsolete] [template-obsolete]
_update_hash_filename_ = instance-obsolete.jinja2.cfg _update_hash_filename_ = instance-obsolete.jinja2.cfg
...@@ -112,7 +112,7 @@ md5sum = dcaac06553a3222b14c0013a13f4a149 ...@@ -112,7 +112,7 @@ md5sum = dcaac06553a3222b14c0013a13f4a149
[enb.jinja2.cfg] [enb.jinja2.cfg]
filename = config/enb.jinja2.cfg filename = config/enb.jinja2.cfg
md5sum = a8e67b3c9373fe4d97066a64d1ff8a98 md5sum = 7edbafa743dc17749ff910aca775abbf
[drb_lte.jinja2.cfg] [drb_lte.jinja2.cfg]
filename = config/drb_lte.jinja2.cfg filename = config/drb_lte.jinja2.cfg
...@@ -145,7 +145,7 @@ md5sum = 36281b03597252cf75169417d02fc28c ...@@ -145,7 +145,7 @@ md5sum = 36281b03597252cf75169417d02fc28c
[ue.jinja2.cfg] [ue.jinja2.cfg]
filename = config/ue.jinja2.cfg filename = config/ue.jinja2.cfg
md5sum = 9bffa00d88ffa57cf1e3b11a24c494b9 md5sum = 62291a11fd36a42464901cdc81338687
[ru_lopcomm_CreateProcessingEle.jinja2.xml] [ru_lopcomm_CreateProcessingEle.jinja2.xml]
_update_hash_filename_ = ru/lopcomm/CreateProcessingEle.jinja2.xml _update_hash_filename_ = ru/lopcomm/CreateProcessingEle.jinja2.xml
...@@ -153,7 +153,7 @@ md5sum = e435990eb0a0d4be41efa9bd16dce09b ...@@ -153,7 +153,7 @@ md5sum = e435990eb0a0d4be41efa9bd16dce09b
[ru_lopcomm_cu_config.jinja2.xml] [ru_lopcomm_cu_config.jinja2.xml]
_update_hash_filename_ = ru/lopcomm/cu_config.jinja2.xml _update_hash_filename_ = ru/lopcomm/cu_config.jinja2.xml
md5sum = 274faf246197cbdd4973b772569daa8e md5sum = 346c911e1ac5e5001a39c8926b44c91e
[software.cfg.html] [software.cfg.html]
_update_hash_filename_ = gadget/software.cfg.html _update_hash_filename_ = gadget/software.cfg.html
......
{%- import 'slaplte.jinja2' as slaplte with context %} {%- import 'slaplte.jinja2' as slaplte with context %}
{%- set B = slaplte.B %}
{%- set J = slaplte.J %} {%- set J = slaplte.J %}
{%- set jcell_ru_ref = slaplte.jcell_ru_ref %} {%- set jcell_ru_ref = slaplte.jcell_ru_ref %}
{%- set cfg = slaplte.cfg %}
{#- for standalone testing via slapos-render-config.py {#- for standalone testing via slapos-render-config.py
NOTE: keep in sync with instance-enb.jinja2.cfg and ru/libinstance.jinja2.cfg #} NOTE: keep in sync with instance-enb.jinja2.cfg and ru/libinstance.jinja2.cfg #}
...@@ -35,13 +35,13 @@ ...@@ -35,13 +35,13 @@
{ {
{%- if cell2.cell_type == 'lte' %} {%- if cell2.cell_type == 'lte' %}
rat: "eutra", 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 }}, n_id_cell: {{ cell2.pci }},
dl_earfcn: {{ cell2.dl_earfcn }}, dl_earfcn: {{ cell2.dl_earfcn }},
tac: {{ cell2.tac }}, tac: {{ cell2.tac }},
{%- elif cell2.cell_type == 'nr' %} {%- elif cell2.cell_type == 'nr' %}
rat: "nr", rat: "nr",
cell_id: {{ cell2.cell_id }}, // -> {{ cell2_ref }} cell_id: {{ cell2.cell_id }}, // -> {{ B(cell2_ref) }}
{%- else %} {%- else %}
{%- do bug('unreachable') %} {%- do bug('unreachable') %}
{%- endif %} {%- endif %}
...@@ -58,13 +58,13 @@ ...@@ -58,13 +58,13 @@
{ {
{%- if ncell.cell_type == 'lte' %} {%- if ncell.cell_type == 'lte' %}
rat: "eutra", rat: "eutra",
cell_id: {{ ncell.e_cell_id }}, // -> {{ peercell_ref }} cell_id: {{ ncell.e_cell_id }}, // -> {{ B(peercell_ref) }}
n_id_cell: {{ ncell.pci }}, n_id_cell: {{ ncell.pci }},
dl_earfcn: {{ ncell.dl_earfcn }}, dl_earfcn: {{ ncell.dl_earfcn }},
tac: {{ ncell.tac }}, tac: {{ ncell.tac }},
{%- elif ncell.cell_type == 'nr' %} {%- elif ncell.cell_type == 'nr' %}
rat: "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 }}, gnb_id_bits: {{ ncell.gnb_id_bits }},
n_id_cell: {{ ncell.pci }}, n_id_cell: {{ ncell.pci }},
dl_nr_arfcn: {{ ncell.dl_nr_arfcn }}, dl_nr_arfcn: {{ ncell.dl_nr_arfcn }},
...@@ -184,7 +184,7 @@ ...@@ -184,7 +184,7 @@
{%- set iru = iru_dict[ru_ref] %} {%- set iru = iru_dict[ru_ref] %}
{%- set ru = iru['_'] %} {%- set ru = iru['_'] %}
// {{ cell_ref }} ({{ ru_ref }}) // {{ B(cell_ref) }} ({{ B(ru_ref) }})
{ {
rf_port: {{ ru._rf_port }}, rf_port: {{ ru._rf_port }},
n_antenna_dl: {{ ru.n_antenna_dl }}, n_antenna_dl: {{ ru.n_antenna_dl }},
...@@ -208,7 +208,7 @@ ...@@ -208,7 +208,7 @@
{%- set cell2 = icell2['_'] %} {%- set cell2 = icell2['_'] %}
{%- if cell2_ref != cell_ref and cell2.cell_type == 'lte' %} {%- 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, cross_carrier_scheduling: false,
}, },
{%- endif %} {%- endif %}
...@@ -222,7 +222,7 @@ ...@@ -222,7 +222,7 @@
{%- set cell2 = icell2['_'] %} {%- set cell2 = icell2['_'] %}
{%- if cell2_ref != cell_ref and cell2.cell_type == 'nr' %} {%- 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 %} {%- endif %}
{%- endfor %} {%- endfor %}
...@@ -298,11 +298,11 @@ ...@@ -298,11 +298,11 @@
manual_ref_signal_power: true, manual_ref_signal_power: true,
{%- endif %} {%- endif %}
drb_config: "{{ cell_ref }}-drb.cfg", drb_config: "{{ B('%s-drb.cfg' % cell_ref) }}",
sib_sched_list: [ sib_sched_list: [
{ {
filename: "{{ cell_ref }}-sib23.asn", filename: "{{ B('%s-sib23.asn' % cell_ref) }}",
si_periodicity: 16, si_periodicity: 16,
}, },
], ],
...@@ -421,7 +421,7 @@ ...@@ -421,7 +421,7 @@
{%- set iru = iru_dict[ru_ref] %} {%- set iru = iru_dict[ru_ref] %}
{%- set ru = iru['_'] %} {%- set ru = iru['_'] %}
// {{ cell_ref }} ({{ ru_ref }}) // {{ B(cell_ref) }} ({{ B(ru_ref) }})
{ {
rf_port: {{ ru._rf_port }}, rf_port: {{ ru._rf_port }},
n_antenna_dl: {{ ru.n_antenna_dl }}, n_antenna_dl: {{ ru.n_antenna_dl }},
...@@ -450,7 +450,7 @@ ...@@ -450,7 +450,7 @@
{%- set cell2 = icell2['_'] %} {%- set cell2 = icell2['_'] %}
{%- if cell2_ref != cell_ref and cell2.cell_type == 'nr' %} {%- 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 %} {%- endif %}
{%- endfor %} {%- endfor %}
...@@ -698,7 +698,7 @@ ...@@ -698,7 +698,7 @@
}, },
drb_config: "{{ cell_ref }}-drb.cfg", drb_config: "{{ B('%s-drb.cfg' % cell_ref) }}",
}, },
{%- endif %} {%- endif %}
......
...@@ -48,7 +48,7 @@ ...@@ -48,7 +48,7 @@
// LTE cells // LTE cells
cell_list: [ cell_list: [
// CELL_a (RU1) // CELL__a (RU1)
{ {
rf_port: 0, rf_port: 0,
n_antenna_dl: 2, n_antenna_dl: 2,
...@@ -68,7 +68,7 @@ ...@@ -68,7 +68,7 @@
// Intra-ENB HO // Intra-ENB HO
{ {
rat: "nr", rat: "nr",
cell_id: 0x02, // -> CELL_b cell_id: 0x02, // -> CELL__b
}, },
// Inter-ENB HO // Inter-ENB HO
...@@ -102,7 +102,7 @@ ...@@ -102,7 +102,7 @@
// Dual Connectivity: LTE + NR // Dual Connectivity: LTE + NR
en_dc_scg_cell_list: [ en_dc_scg_cell_list: [
{ {
cell_id: 0x02, // + CELL_b cell_id: 0x02, // + CELL__b
}, },
], ],
...@@ -140,11 +140,11 @@ ...@@ -140,11 +140,11 @@
srs_hopping_bandwidth: 0, srs_hopping_bandwidth: 0,
}, },
drb_config: "CELL_a-drb.cfg", drb_config: "CELL__a-drb.cfg",
sib_sched_list: [ sib_sched_list: [
{ {
filename: "CELL_a-sib23.asn", filename: "CELL__a-sib23.asn",
si_periodicity: 16, si_periodicity: 16,
}, },
], ],
...@@ -242,7 +242,7 @@ ...@@ -242,7 +242,7 @@
// NR cells // NR cells
nr_cell_list: [ nr_cell_list: [
// CELL_b (RU2) // CELL__b (RU2)
{ {
rf_port: 1, rf_port: 1,
n_antenna_dl: 2, n_antenna_dl: 2,
...@@ -267,7 +267,7 @@ ...@@ -267,7 +267,7 @@
// Intra-ENB HO // Intra-ENB HO
{ {
rat: "eutra", rat: "eutra",
cell_id: 0x1001201, // -> CELL_a cell_id: 0x1001201, // -> CELL__a
n_id_cell: 1, n_id_cell: 1,
dl_earfcn: 38050, dl_earfcn: 38050,
tac: 0x1234, tac: 0x1234,
...@@ -438,7 +438,7 @@ ...@@ -438,7 +438,7 @@
}, },
drb_config: "CELL_b-drb.cfg", drb_config: "CELL__b-drb.cfg",
}, },
], ],
......
...@@ -12,8 +12,8 @@ ...@@ -12,8 +12,8 @@
// XXX vvv <- ru.txrx_active ? XXX how to handle txrx_active for SDR ? // 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) // (tx_gain=-1000 does not work - it still sets tx_gain to min.possible value 14)
name: "sdr", name: "sdr",
// _UCELL1_ru 2T1R (sdr) // __UCELL1__ru 2T1R (sdr)
// _UCELL2_ru 2T2R (sdr) // __UCELL2__ru 2T2R (sdr)
args: "dev0=/dev/sdr0,dev1=/dev/sdr2", args: "dev0=/dev/sdr0,dev1=/dev/sdr2",
rx_antenna:"tx_rx", rx_antenna:"tx_rx",
tdd_tx_mod: 1, tdd_tx_mod: 1,
......
{%- import 'slaplte.jinja2' as slaplte with context %} {%- import 'slaplte.jinja2' as slaplte with context %}
{%- set B = slaplte.B %}
{%- set J = slaplte.J %} {%- set J = slaplte.J %}
{%- set jcell_ru_ref = slaplte.jcell_ru_ref %} {%- set jcell_ru_ref = slaplte.jcell_ru_ref %}
...@@ -39,7 +40,7 @@ ...@@ -39,7 +40,7 @@
{%- set iru = iru_dict[ru_ref] %} {%- set iru = iru_dict[ru_ref] %}
{%- set ru = iru['_'] %} {%- set ru = iru['_'] %}
// {{ cell_ref }} // {{ B(cell_ref) }}
{ {
rf_port: {{ ru._rf_port }}, rf_port: {{ ru._rf_port }},
n_antenna_dl: {{ ru.n_antenna_dl }}, n_antenna_dl: {{ ru.n_antenna_dl }},
...@@ -69,7 +70,7 @@ ...@@ -69,7 +70,7 @@
{%- set ru_ref = J(jcell_ru_ref(icell)) %} {%- set ru_ref = J(jcell_ru_ref(icell)) %}
{%- set iru = iru_dict[ru_ref] %} {%- set iru = iru_dict[ru_ref] %}
{%- set ru = iru['_'] %} {%- set ru = iru['_'] %}
// {{ cell_ref }} // {{ B(cell_ref) }}
{ {
rf_port: {{ ru._rf_port }}, rf_port: {{ ru._rf_port }},
n_antenna_dl: {{ ru.n_antenna_dl }}, n_antenna_dl: {{ ru.n_antenna_dl }},
...@@ -91,7 +92,7 @@ ...@@ -91,7 +92,7 @@
ue_list: [ ue_list: [
{%- for ue_ref, iue in iue_dict|dictsort %} {%- for ue_ref, iue in iue_dict|dictsort %}
{%- set ue = iue['_'] %} {%- set ue = iue['_'] %}
// {{ ue_ref }} // {{ B(ue_ref) }}
{ {
sim_algo: "{{ ue.sim_algo }}", sim_algo: "{{ ue.sim_algo }}",
opc: "{{ ue.opc }}", opc: "{{ ue.opc }}",
......
...@@ -189,6 +189,7 @@ context = ...@@ -189,6 +189,7 @@ context =
key slapparameter_dict slap-configuration:configuration key slapparameter_dict slap-configuration:configuration
key gtp_addr_v6 slap-configuration:ipv6-random key gtp_addr_v6 slap-configuration:ipv6-random
raw gtp_addr_v4 {{ lan_ipv4 }} raw gtp_addr_v4 {{ lan_ipv4 }}
import xbuildout xbuildout
import netaddr netaddr import netaddr netaddr
${:extra-context} ${:extra-context}
...@@ -200,14 +201,18 @@ url = ${enb-config-dl:target} ...@@ -200,14 +201,18 @@ url = ${enb-config-dl:target}
url = {{ enb_template }} url = {{ enb_template }}
{% endif %} {% endif %}
output = ${directory:etc}/enb.cfg 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 = import-list =
rawfile slaplte.jinja2 {{ slaplte_template }} 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] [publish-connection-information]
...@@ -221,8 +226,8 @@ enb-ipv4 = {{ lan_ipv4 }} ...@@ -221,8 +226,8 @@ enb-ipv4 = {{ lan_ipv4 }}
amarisoft-version = {{ lte_version }} amarisoft-version = {{ lte_version }}
license-expiration = {{ lte_expiration }} license-expiration = {{ lte_expiration }}
monitor-gadget-url = ${:monitor-base-url}/gadget/software.cfg.html monitor-gadget-url = ${:monitor-base-url}/gadget/software.cfg.html
ru-list = {{ rulib.iru_dict.keys() | sort | join(', ') }} ru-list = {{ dumps(rulib.iru_dict.keys() | sort) }}
cell-list = {{ rulib.icell_dict.keys() | sort | join(', ') }} cell-list = {{ dumps(rulib.icell_dict.keys() | sort) }}
# TODO peer-list peer-cell-list # TODO peer-list peer-cell-list
peer-list = XXX peer-list = XXX
peer-cell-list = XXX peer-cell-list = XXX
......
...@@ -107,6 +107,7 @@ context = ...@@ -107,6 +107,7 @@ context =
section slap_configuration slap-configuration section slap_configuration slap-configuration
section pub_info publish-connection-information section pub_info publish-connection-information
key slapparameter_dict slap-configuration:configuration key slapparameter_dict slap-configuration:configuration
import xbuildout xbuildout
${:extra-context} ${:extra-context}
[lte-ue-config] [lte-ue-config]
...@@ -117,13 +118,16 @@ url = ${ue-config-dl:target} ...@@ -117,13 +118,16 @@ url = ${ue-config-dl:target}
url = {{ ue_template }} url = {{ ue_template }}
{% endif %} {% endif %}
output = ${directory:etc}/ue.cfg 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 = import-list =
rawfile slaplte.jinja2 {{ slaplte_template }} 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] [publish-connection-information]
......
...@@ -27,6 +27,7 @@ sys.path[0:0] = [ ...@@ -27,6 +27,7 @@ sys.path[0:0] = [
'/srv/slapgrid/slappart91/srv/project/slapos', '/srv/slapgrid/slappart91/srv/project/slapos',
'/srv/slapgrid/slappart91/srv/project/slapos/software/ors-amarisoft/test', '/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/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/requests-2.31.0-py3.9.egg',
'/srv/slapgrid/slappart91/srv/runner/software/45a1e838784afb18daf420009d925c78/eggs/testfixtures-6.11.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' ...@@ -81,6 +81,19 @@ RU2['mac_addr'] = '90:A9:F7:C0:00:03'
iru1 = iENB(eref('RU1'), RU1) iru1 = iENB(eref('RU1'), RU1)
iru2 = iENB(eref('RU2'), RU2) 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 # Cells
CELL1 = { CELL1 = {
......
...@@ -108,6 +108,18 @@ ...@@ -108,6 +108,18 @@
"default": 0 "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 @@ ...@@ -41,7 +41,7 @@
{%- set pretty_name = name.removeprefix('%s.' % root) %} {%- set pretty_name = name.removeprefix('%s.' % root) %}
{{ part('promise-'+name) }} {{ part('promise-'+name) }}
<= monitor-promise-base <= monitor-promise-base
name = {{ pretty_name }}.py name = {{ dumps('%s.py' % pretty_name) }}
config-testing = {{ testing }} config-testing = {{ testing }}
config-stats-period = {{ slapparameter_dict.get("enb_stats_fetch_period", 60) }} config-stats-period = {{ slapparameter_dict.get("enb_stats_fetch_period", 60) }}
{%- endmacro %} {%- endmacro %}
...@@ -153,7 +153,8 @@ context = ...@@ -153,7 +153,8 @@ context =
import netaddr netaddr import netaddr netaddr
section directory directory section directory directory
section vtap_jdict vtap_jdict section vtap_jdict vtap_jdict
json iru_dict {{ iru_dict | tojson }} key iru_dict :iru_dict
iru_dict = {{ dumps(iru_dict) }}
{{ part('dnsmasq-service') }} {{ part('dnsmasq-service') }}
recipe = slapos.cookbook:wrapper recipe = slapos.cookbook:wrapper
...@@ -185,7 +186,7 @@ hash-files = ...@@ -185,7 +186,7 @@ hash-files =
{%- endif %} {%- endif %}
{%- endfor %} {%- 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' %} {%- if ru.ru_link_type == 'sdr' %}
{%- for (i, n) in enumerate(ru.sdr_dev_list) %} {%- for (i, n) in enumerate(ru.sdr_dev_list) %}
{{ promise('%s-sdr-busy%s' % (ru_ref, '-%d' % (i+1) if i > 0 else '')) }} {{ 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) }} ...@@ -229,13 +230,13 @@ config-max-rx-sample-db = {{ slapparameter_dict.get("max_rx_sample_db", 0) }}
{#- publish information about RU #} {#- publish information about RU #}
{{ part('publish-%s' % ru_ref) }} {{ part('publish-%s' % ru_ref) }}
recipe = slapos.cookbook:publish.serialised recipe = slapos.cookbook:publish.serialised
-slave-reference = {{ iru.slave_reference }} -slave-reference = {{ dumps(iru.slave_reference) }}
enb = {{ root }} {{ slap_configuration['slap-software-type'] }} = {{ dumps(root) }}
{%- set iru_icell_ref_list = [] %} {%- set iru_icell_ref_list = [] %}
{%- for icell in iru_icell_list %} {%- for icell in iru_icell_list %}
{%- do iru_icell_ref_list.append(J(jref_of_shared(icell))) %} {%- do iru_icell_ref_list.append(J(jref_of_shared(icell))) %}
{%- endfor %} {%- endfor %}
cell-list = {{ iru_icell_ref_list | join(', ') }} cell-list = {{ dumps(iru_icell_ref_list) }}
{%- if ru.ru_link_type == 'cpri' %} {%- if ru.ru_link_type == 'cpri' %}
ipv6 = ${vtap.{{ ru.cpri_link._tap }}:gateway} ipv6 = ${vtap.{{ ru.cpri_link._tap }}:gateway}
{%- endif %} {%- endif %}
...@@ -255,31 +256,38 @@ ipv6 = ${vtap.{{ ru.cpri_link._tap }}:gateway} ...@@ -255,31 +256,38 @@ ipv6 = ${vtap.{{ ru.cpri_link._tap }}:gateway}
{{ part('drb-config-%s' % cell_ref) }} {{ part('drb-config-%s' % cell_ref) }}
<= config-base <= config-base
url = {{ {'lte': drb_lte_template, 'nr': drb_nr_template} [cell.cell_type] }} 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 = extra-context =
json cell_ref {{ cell_ref | tojson }} key cell_ref :cell_ref
json cell {{ cell | tojson }} key cell :cell
json ru_ref {{ ru_ref | tojson }} key ru_ref :ru_ref
json ru {{ ru | tojson }} 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) }} {{ part('sib23-config-%s' % cell_ref) }}
<= config-base <= config-base
url = {{ sib23_template }} url = {{ sib23_template }}
output = ${directory:etc}/{{cell_ref}}-sib23.asn output = ${directory:etc}/{{B('%s-sib23.asn' % cell_ref)}}
extra-context = extra-context =
json cell_ref {{ cell_ref | tojson }} key cell_ref :cell_ref
json cell {{ cell | tojson }} key cell :cell
json ru_ref {{ ru_ref | tojson }} key ru_ref :ru_ref
json ru {{ ru | tojson }} key ru :ru
cell_ref = {{ dumps(cell_ref) }}
cell = {{ dumps(cell ) }}
ru_ref = {{ dumps(ru_ref ) }}
ru = {{ dumps(ru ) }}
{%- endif %} {%- endif %}
{#- publish information about the cell #} {#- publish information about the cell #}
{{ part('publish-%s' % cell_ref) }} {{ part('publish-%s' % cell_ref) }}
recipe = slapos.cookbook:publish.serialised recipe = slapos.cookbook:publish.serialised
-slave-reference = {{ icell.slave_reference }} -slave-reference = {{ dumps(icell.slave_reference) }}
enb = {{ root }} {{ slap_configuration['slap-software-type'] }} = {{ dumps(root) }}
ru = {{ ru_ref }} ru = {{ dumps(ru_ref) }}
# XXX enb -> ue in case of uesim
# XXX +error # XXX +error
{%- endfor %} {%- endfor %}
...@@ -321,7 +329,8 @@ context = ...@@ -321,7 +329,8 @@ context =
raw stats_period {{ slapparameter_dict.get("enb_stats_fetch_period", 60) }} raw stats_period {{ slapparameter_dict.get("enb_stats_fetch_period", 60) }}
raw testing {{ testing }} raw testing {{ testing }}
raw python_path {{ buildout_directory}}/bin/pythonwitheggs 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 mode = 0775
url = {{ ru_amarisoft_stats_template }} url = {{ ru_amarisoft_stats_template }}
output = ${directory:bin}/amarisoft-stats.py output = ${directory:bin}/amarisoft-stats.py
......
...@@ -124,6 +124,7 @@ ...@@ -124,6 +124,7 @@
<downlink-radio-frame-offset>0</downlink-radio-frame-offset> <downlink-radio-frame-offset>0</downlink-radio-frame-offset>
<downlink-sfn-offset>0</downlink-sfn-offset> <downlink-sfn-offset>0</downlink-sfn-offset>
<!-- <gain>{{ ru.rx_gain }}</gain> --> <!-- <gain>{{ ru.rx_gain }}</gain> -->
<!-- TODO(lu.xu): clarify with Lopcomm regaring rx gain -->
<gain-correction>0.0</gain-correction> <gain-correction>0.0</gain-correction>
<n-ta-offset>0</n-ta-offset> <n-ta-offset>0</n-ta-offset>
</rx-array-carriers> </rx-array-carriers>
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
"tx_gain", "tx_gain",
"rx_gain", "rx_gain",
"cpri_link",
"mac_addr" "mac_addr"
], ],
...@@ -50,11 +51,6 @@ ...@@ -50,11 +51,6 @@
} }
}, },
"mac_addr": {
"title": "RU MAC address",
"description": "RU MAC address used for NETCONF",
"type": "string"
},
"reset_schedule": { "reset_schedule": {
"title": "Cron schedule for RRH reset", "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", "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 ...@@ -23,11 +23,11 @@ config-port = 830
[{{ B('%s-software-template' % ru_ref) }}] [{{ B('%s-software-template' % ru_ref) }}]
recipe = slapos.recipe.template:jinja2 recipe = slapos.recipe.template:jinja2
extensions = jinja2.ext.do extensions = jinja2.ext.do
_logbase = ${directory:var}/log/{{ru_ref}}-software _logbase = ${directory:var}/log/{{B('%s-software' % ru_ref)}}
log-output = ${:_logbase}.log log-output = ${:_logbase}.log
software-reply-json-log-output = ${:_logbase}-reply.json.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}} 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 = context =
section directory directory section directory directory
section vtap vtap.{{ ru.cpri_link._tap }} section vtap vtap.{{ ru.cpri_link._tap }}
...@@ -43,7 +43,7 @@ context = ...@@ -43,7 +43,7 @@ context =
import netaddr netaddr import netaddr netaddr
mode = 0775 mode = 0775
url = {{ ru_lopcomm_software_template }} 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('%s-firmware' % ru_ref) }}
promise = check_command_execute promise = check_command_execute
...@@ -67,17 +67,19 @@ url = ${ {{-B('%s-cu-config-dl' % ru_ref)}}:target} ...@@ -67,17 +67,19 @@ url = ${ {{-B('%s-cu-config-dl' % ru_ref)}}:target}
{% else %} {% else %}
url = {{ ru_lopcomm_cu_config_template }} url = {{ ru_lopcomm_cu_config_template }}
{% endif %} {% endif %}
output = ${directory:etc}/{{ru_ref}}-cu_config.xml output = ${directory:etc}/{{B('%s-cu_config.xml' % ru_ref)}}
extra-context = extra-context =
import xearfcn_module xlte.earfcn import xearfcn_module xlte.earfcn
import xnrarfcn_module xlte.nrarfcn import xnrarfcn_module xlte.nrarfcn
json ru {{ ru | tojson }} key ru :ru
json cell {{ cell | tojson }} key cell :cell
ru = {{ dumps(ru) }}
cell = {{ dumps(cell) }}
[{{ B('%s-config-template' % ru_ref) }}] [{{ B('%s-config-template' % ru_ref) }}]
recipe = slapos.recipe.template:jinja2 recipe = slapos.recipe.template:jinja2
extensions = jinja2.ext.do 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 = context =
section directory directory section directory directory
section vtap vtap.{{ ru.cpri_link._tap }} section vtap vtap.{{ ru.cpri_link._tap }}
...@@ -90,7 +92,7 @@ context = ...@@ -90,7 +92,7 @@ context =
import netaddr netaddr import netaddr netaddr
mode = 0775 mode = 0775
url = {{ ru_lopcomm_config_template }} 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('%s-config-log' % ru_ref) }}
promise = check_lopcomm_config_log promise = check_lopcomm_config_log
...@@ -102,7 +104,7 @@ config-config-log = ${ {{-B('%s-config-template' % ru_ref)}}:log-output} ...@@ -102,7 +104,7 @@ config-config-log = ${ {{-B('%s-config-template' % ru_ref)}}:log-output}
[{{ B('%s-stats-template' % ru_ref) }}] [{{ B('%s-stats-template' % ru_ref) }}]
recipe = slapos.recipe.template:jinja2 recipe = slapos.recipe.template:jinja2
extensions = jinja2.ext.do extensions = jinja2.ext.do
_logbase = ${directory:var}/log/{{ru_ref}} _logbase = ${directory:var}/log/{{B('%s' % ru_ref)}}
log-output = ${:_logbase}-stats.log log-output = ${:_logbase}-stats.log
json-log-output = ${:_logbase}-stats.json.log json-log-output = ${:_logbase}-stats.json.log
cfg-json-log-output = ${:_logbase}-config.json.log cfg-json-log-output = ${:_logbase}-config.json.log
...@@ -110,7 +112,7 @@ supervision-json-log-output = ${:_logbase}-supervision.json.log ...@@ -110,7 +112,7 @@ supervision-json-log-output = ${:_logbase}-supervision.json.log
ncsession-json-log-output = ${:_logbase}-ncsession.json.log ncsession-json-log-output = ${:_logbase}-ncsession.json.log
software-json-log-output = ${:_logbase}-software.json.log software-json-log-output = ${:_logbase}-software.json.log
supervision-reply-json-log-output = ${:_logbase}-supervision-reply.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 = context =
section directory directory section directory directory
section vtap vtap.{{ ru.cpri_link._tap }} section vtap vtap.{{ ru.cpri_link._tap }}
...@@ -129,12 +131,12 @@ context = ...@@ -129,12 +131,12 @@ context =
import netaddr netaddr import netaddr netaddr
mode = 0775 mode = 0775
url = {{ ru_lopcomm_stats_template }} 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) }} {{ part('%s-stats-service' % ru_ref) }}
recipe = slapos.cookbook:wrapper recipe = slapos.cookbook:wrapper
command-line = ${ {{-B('%s-stats-template' % ru_ref)}}:output} 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 mode = 0775
hash-files = hash-files =
${:command-line} ${:command-line}
...@@ -179,7 +181,7 @@ config-stats-log = ${ {{-B('%s-stats-template' % ru_ref)}}:log-output} ...@@ -179,7 +181,7 @@ config-stats-log = ${ {{-B('%s-stats-template' % ru_ref)}}:log-output}
[{{ B('%s-reset-info-template' % ru_ref) }}] [{{ B('%s-reset-info-template' % ru_ref) }}]
recipe = slapos.recipe.template:jinja2 recipe = slapos.recipe.template:jinja2
extensions = jinja2.ext.do 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 log-output = ${:_logbase}.log
json-log-output = ${:_logbase}.json.log json-log-output = ${:_logbase}.json.log
context = context =
...@@ -191,12 +193,12 @@ context = ...@@ -191,12 +193,12 @@ context =
import netaddr netaddr import netaddr netaddr
mode = 0775 mode = 0775
url = {{ ru_lopcomm_reset_info_template }} 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) }}] [{{ B('%s-reset-template' % ru_ref) }}]
recipe = slapos.recipe.template:jinja2 recipe = slapos.recipe.template:jinja2
extensions = jinja2.ext.do extensions = jinja2.ext.do
_logbase = ${directory:var}/log/{{ru_ref}}-reset _logbase = ${directory:var}/log/{{B('%s-reset' % ru_ref)}}
log-output = ${:_logbase}.log log-output = ${:_logbase}.log
json-log-output = ${:_logbase}.json.log json-log-output = ${:_logbase}.json.log
context = context =
...@@ -207,19 +209,19 @@ context = ...@@ -207,19 +209,19 @@ context =
import netaddr netaddr import netaddr netaddr
mode = 0775 mode = 0775
url = {{ ru_lopcomm_reset_template }} 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) }} {{ part('%s-reset-cron' % ru_ref) }}
recipe = slapos.cookbook:cron.d recipe = slapos.cookbook:cron.d
cron-entries = ${cron:cron-entries} cron-entries = ${cron:cron-entries}
name = {{ru_ref}}-reset name = {{B('%s-reset' % ru_ref)}}
frequency = {{ ru.reset_schedule }} frequency = {{ ru.reset_schedule }}
command = {{ buildout_directory}}/bin/pythonwitheggs ${ {{-B('%s-reset-template' % ru_ref)}}:output} command = {{ buildout_directory}}/bin/pythonwitheggs ${ {{-B('%s-reset-template' % ru_ref)}}:output}
{{ part('%s-reset-info-service' % ru_ref) }} {{ part('%s-reset-info-service' % ru_ref) }}
recipe = slapos.cookbook:wrapper recipe = slapos.cookbook:wrapper
command-line = ${ {{- ru_ref}}-reset-info-template:output} command-line = ${ {{-B('%s-reset-info-template' % ru_ref)}}:output}
wrapper-path = ${directory:service}/{{ru_ref}}-reset-info wrapper-path = ${directory:service}/{{B('%s-reset-info' % ru_ref)}}
mode = 0775 mode = 0775
hash-files = hash-files =
${:command-line} ${:command-line}
......
...@@ -10,7 +10,10 @@ ...@@ -10,7 +10,10 @@
"n_antenna_dl", "n_antenna_dl",
"n_antenna_ul", "n_antenna_ul",
"tx_gain", "tx_gain",
"rx_gain" "rx_gain",
"cpri_link",
"mac_addr"
], ],
"properties": { "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 # 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 # it under the terms of the GNU General Public License version 3, or (at your
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
- encode/decode convert string to/from form, that is suitable to be used in - encode/decode convert string to/from form, that is suitable to be used in
names of buildout sections. names of buildout sections.
- XXX quote
""" """
...@@ -60,6 +59,13 @@ ...@@ -60,6 +59,13 @@
# #
# # referring to <ru_ref>-stats # # referring to <ru_ref>-stats
# ${ {{-B('%s-stats' % ru_ref)}}:output} # ${ {{-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: def encode(s: str) -> str:
s = s.encode('utf-8') s = s.encode('utf-8')
outv = [] outv = []
...@@ -128,18 +134,6 @@ def _decode(s): ...@@ -128,18 +134,6 @@ def _decode(s):
return out 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 import re
...@@ -198,8 +192,3 @@ def test_encode(): ...@@ -198,8 +192,3 @@ def test_encode():
def _(cause): def _(cause):
assert isinstance(cause, UnicodeDecodeError) assert isinstance(cause, UnicodeDecodeError)
checkbad(x, _) checkbad(x, _)
def test_quote():
# XXX
pass
...@@ -79,6 +79,10 @@ ...@@ -79,6 +79,10 @@
} }
%} %}
{#- XXX explain #}
{%- set B = xbuildout.encode %}
{#- J is used around macro calls to retrieve returned objects. {#- J is used around macro calls to retrieve returned objects.
It is needed to workaround jinja2 limitation that macro can return only It is needed to workaround jinja2 limitation that macro can return only
...@@ -419,7 +423,7 @@ ...@@ -419,7 +423,7 @@
{%- set rx_gainv = [] %} {#- rx_gain by rx channel #} {%- set rx_gainv = [] %} {#- rx_gain by rx channel #}
{%- for (ru_ref, iru) in iru_dict.items() | sort(attribute="1._._rf_port") %} {%- for (ru_ref, iru) in iru_dict.items() | sort(attribute="1._._rf_port") %}
{%- set ru = iru['_'] %} {%- 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' %} {%- if ru.ru_type == 'sdr' %}
{%- do ru_sdr_dict.update({len(dev_argv): ru}) %} {%- do ru_sdr_dict.update({len(dev_argv): ru}) %}
{%- for n in ru.sdr_dev_list %} {%- for n in ru.sdr_dev_list %}
......
...@@ -6,7 +6,12 @@ ...@@ -6,7 +6,12 @@
import zc.buildout.buildout # XXX workaround for https://lab.nexedi.com/nexedi/slapos.recipe.template/merge_requests/9 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 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. # j2render renders config/<src> into config/out/<out> with provided json parameters.
...@@ -19,6 +24,7 @@ def j2render(src, out, jcfg): ...@@ -19,6 +24,7 @@ def j2render(src, out, jcfg):
textctx = '' textctx = ''
for k, v in ctx.items(): for k, v in ctx.items():
textctx += 'json %s %s\n' % (k, json.dumps(v)) textctx += 'json %s %s\n' % (k, json.dumps(v))
textctx += 'import xbuildout xbuildout\n'
textctx += 'import json_module json\n' textctx += 'import json_module json\n'
textctx += 'import nrarfcn_module nrarfcn\n' textctx += 'import nrarfcn_module nrarfcn\n'
textctx += 'import xearfcn_module xlte.earfcn\n' textctx += 'import xearfcn_module xlte.earfcn\n'
...@@ -466,11 +472,11 @@ def do_enb(): ...@@ -466,11 +472,11 @@ def do_enb():
'ru': ru, 'ru': ru,
}) })
j2render('drb_%s.jinja2.cfg' % cell['cell_type'], j2render('drb_%s.jinja2.cfg' % cell['cell_type'],
'%s-drb.cfg' % cell_ref, B('%s-drb.cfg' % cell_ref),
jctx) jctx)
j2render('sib23.jinja2.asn', j2render('sib23.jinja2.asn',
'%s-sib23.asn' % cell_ref, B('%s-sib23.asn' % cell_ref),
jctx) jctx)
......
...@@ -46,6 +46,7 @@ setup( ...@@ -46,6 +46,7 @@ setup(
'slapos.libnetworkcache', 'slapos.libnetworkcache',
'slapos.cookbook', 'slapos.cookbook',
'pcpp', 'pcpp',
'xmltodict',
], ],
zip_safe=True, zip_safe=True,
test_suite='test', 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 # 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 # it under the terms of the GNU General Public License version 3, or (at your
...@@ -16,16 +16,38 @@ ...@@ -16,16 +16,38 @@
# See COPYING file for full licensing terms. # See COPYING file for full licensing terms.
# See https://www.nexedi.com/licensing for rationale and options. # 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 os
import json import json
import io import io
import yaml import yaml
import pcpp import pcpp
import xmltodict
import sys
sys.path.insert(0, '../ru')
import xbuildout
import unittest import unittest
from slapos.testing.testcase import makeModuleSetUpAndTestCaseClass from slapos.testing.testcase import makeModuleSetUpAndTestCaseClass
setUpModule, AmariTestCase = makeModuleSetUpAndTestCaseClass( setUpModule, _AmariTestCase = makeModuleSetUpAndTestCaseClass(
os.path.abspath( os.path.abspath(
os.path.join(os.path.dirname(__file__), '..', 'software.cfg'))) os.path.join(os.path.dirname(__file__), '..', 'software.cfg')))
...@@ -37,7 +59,7 @@ setUpModule, AmariTestCase = makeModuleSetUpAndTestCaseClass( ...@@ -37,7 +59,7 @@ setUpModule, AmariTestCase = makeModuleSetUpAndTestCaseClass(
# - BW indicates specified bandwidth. # - BW indicates specified bandwidth.
# - CENB indicates a ENB-kind cell. # - CENB indicates a ENB-kind cell.
# - CUE indicates an UE-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. # - LTE_PEER/NR_PEER indicate an LTE/NR ENB-PEER-kind cell.
# - X2_PEER/XN_PEER indicate an LTE/NR ENB peer. # - X2_PEER/XN_PEER indicate an LTE/NR ENB peer.
...@@ -73,16 +95,14 @@ def CENB(cell_id, pci): ...@@ -73,16 +95,14 @@ def CENB(cell_id, pci):
} }
# CUE indicates an UE-kind cell. # 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): def TAC(tac):
return { return {
'tac': '0x%x' % tac, 'tac': '0x%x' % tac,
} }
CUE = {'cell_kind': 'ue'}
# LTE_PEER/NR_PEER return basic parameters to indicate an LTE/NR ENB-PEER-kind cell. # LTE_PEER/NR_PEER return basic parameters to indicate an LTE/NR ENB-PEER-kind cell.
def LTE_PEER(e_cell_id, pci, tac): def LTE_PEER(e_cell_id, pci, tac):
return { return {
...@@ -112,88 +132,33 @@ def XN_PEER(xn_addr): ...@@ -112,88 +132,33 @@ def XN_PEER(xn_addr):
'xn_addr': xn_addr, 'xn_addr': xn_addr,
} }
# ---- # --------
# AmariTestCase is base class for all tests.
# XXX doc class AmariTestCase(_AmariTestCase):
# XXX approach is to test generated enb.cfg maxDiff = None # show full diff in test run log on an error
class ENBTestCase(AmariTestCase):
maxDiff = None # want to see full diff in test run log on an error
# stress correctness of ru_ref/cell_ref/... usage throughout all places in # stress correctness of ru_ref/cell_ref/... usage throughout all places in
# buildout code - special characters should not lead to wrong templates or # buildout code - special characters should not lead to wrong templates or
# code injection. # code injection.
default_partition_reference = AmariTestCase.default_partition_reference + \ default_partition_reference = _AmariTestCase.default_partition_reference + \
' ${a:b}\n[c]\n;' ' ${a:b}\n[c]\n;'
# XXX temp # faster edit/try cycle when enabled (handy during development)
if 0:
instance_max_retry = 1 instance_max_retry = 1
report_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 @classmethod
def requestDefaultInstance(cls, state='started'): def requestDefaultInstance(cls, state='started'):
inst = super().requestDefaultInstance(state=state) inst = super().requestDefaultInstance(state=state)
cls.requestAllShared(inst) cls.requestAllShared(inst)
return 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 @classmethod
def requestAllShared(cls, imain): def requestAllShared(cls, imain):
def _(subref, ctx): raise NotImplementedError
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))
# requestShared requests one shared instance over imain with specified subreference and parameters. # requestShared requests one shared instance over imain with specified subreference and parameters.
@classmethod @classmethod
...@@ -222,55 +187,150 @@ class ENBTestCase(AmariTestCase): ...@@ -222,55 +187,150 @@ class ENBTestCase(AmariTestCase):
assert path[:1] != '/', path assert path[:1] != '/', path
return '%s/%s' % (cls.computer_partition_root_path, 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( assertMatch(t, t.enb_cfg, dict(
enb_id=0x17, gnb_id=0x23, gnb_id_bits=30, enb_id=0x17, gnb_id=0x23, gnb_id_bits=30,
x2_peers=['44.1.1.1'], xn_peers=['55.1.1.1'], 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 # basic cell parameters
def test_enb_conf_cell(t): def test_enb_cfg_cell(t):
assertMatch(t, t.enb_cfg['cell_list'], [ assertMatch(t, t.enb_cfg['cell_list'], [
dict( # CELL1 dict( # CELL1
uldl_config=NO, rf_port=0, n_antenna_dl=4, n_antenna_ul=2, uldl_config=NO, rf_port=0, n_antenna_dl=4, n_antenna_ul=2,
dl_earfcn=100, ul_earfcn=18100, dl_earfcn=100, ul_earfcn=18100,
n_rb_dl=25, n_rb_dl=25,
cell_id=0x1, n_id_cell=0x11, tac=0x101, 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 dict( # CELL2
uldl_config=2, rf_port=1, n_antenna_dl=4, n_antenna_ul=2, 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, n_rb_dl=50,
cell_id=0x2, n_id_cell=0x12, tac=0x102, 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'], [ assertMatch(t, t.enb_cfg['nr_cell_list'], [
dict( # CELL3 dict( # CELL3
tdd_ul_dl_config=NO, rf_port=2, n_antenna_dl=4, n_antenna_ul=2, 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, bandwidth=15,
cell_id=0x3, n_id_cell=0x13, tac=NO, 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 dict( # CELL4
...@@ -278,52 +338,52 @@ class ENBTestCase(AmariTestCase): ...@@ -278,52 +338,52 @@ class ENBTestCase(AmariTestCase):
period=5, dl_slots=7, dl_symbols=6, ul_slots=2, ul_symbols=4, 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, 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, bandwidth=20,
cell_id=0x4, n_id_cell=0x14, tac=NO, 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 # Carrier Aggregation
def test_enb_conf_ca(t): def test_enb_cfg_ca(t):
assertMatch(t, t.enb_cfg['cell_list'], [ assertMatch(t, t.enb_cfg['cell_list'], [
{ # CELL1 { # CELL1
'scell_list': [{'cell_id': 0x2}], # LTE + LTE 'scell_list': [{'cell_id': 2}], # LTE + LTE
'en_dc_scg_cell_list': [{'cell_id': 0x3}, {'cell_id': 0x4}], # LTE + NR 'en_dc_scg_cell_list': [{'cell_id': 3}, {'cell_id': 4}], # LTE + NR
}, },
{ # CELL2 { # CELL2
'scell_list': [{'cell_id': 0x1}], # LTE + LTE 'scell_list': [{'cell_id': 1}], # LTE + LTE
'en_dc_scg_cell_list': [{'cell_id': 0x3}, {'cell_id': 0x4}], # LTE + NR 'en_dc_scg_cell_list': [{'cell_id': 3}, {'cell_id': 4}], # LTE + NR
}, },
]) ])
assertMatch(t, t.enb_cfg['nr_cell_list'], [ assertMatch(t, t.enb_cfg['nr_cell_list'], [
{ # CELL3 { # CELL3
'scell_list': [{'cell_id': 0x4}], # NR + NR 'scell_list': [{'cell_id': 4}], # NR + NR
}, },
{ # CELL4 { # CELL4
'scell_list': [{'cell_id': 0x3}], # NR + NR 'scell_list': [{'cell_id': 3}], # NR + NR
}, },
]) ])
# Handover # Handover
def test_enb_conf_ho(t): def test_enb_cfg_ho(t):
assertMatch(t, t.enb_cfg['cell_list'], [ assertMatch(t, t.enb_cfg['cell_list'], [
{ # CELL1 { # CELL1
'ncell_list': [ 'ncell_list': [
dict(rat='eutra', cell_id= 0x1702, n_id_cell=0x12, dl_earfcn=36100, tac=0x102), # CELL2 dict(rat='eutra', cell_id= 0x1702, n_id_cell=0x12, dl_earfcn=40200, tac=0x102), # CELL2
dict(rat='nr', cell_id= 0x03), # CELL3 dict(rat='nr', cell_id= 3), # CELL3
dict(rat='nr', cell_id= 0x04), # CELL4 dict(rat='nr', cell_id= 4), # CELL4
] + t.ho_inter, ] + t.ho_inter,
}, },
{ # CELL2 { # CELL2
'ncell_list': [ 'ncell_list': [
dict(rat='eutra', cell_id= 0x1701, n_id_cell=0x11, dl_earfcn= 100, tac=0x101), # CELL1 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= 3), # CELL3
dict(rat='nr', cell_id= 0x04), # CELL4 dict(rat='nr', cell_id= 4), # CELL4
] + t.ho_inter, ] + t.ho_inter,
}, },
]) ])
...@@ -331,46 +391,47 @@ class ENBTestCase(AmariTestCase): ...@@ -331,46 +391,47 @@ class ENBTestCase(AmariTestCase):
{ # CELL3 { # CELL3
'ncell_list': [ 'ncell_list': [
dict(rat='eutra', cell_id= 0x1701, n_id_cell=0x11, dl_earfcn= 100, tac=0x101), # CELL1 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='eutra', cell_id= 0x1702, n_id_cell=0x12, dl_earfcn=40200, tac=0x102), # CELL2
dict(rat='nr', cell_id= 0x04), # CELL4 dict(rat='nr', cell_id= 4), # CELL4
] + t.ho_inter, ] + t.ho_inter,
}, },
{ # CELL4 { # CELL4
'ncell_list': [ 'ncell_list': [
dict(rat='eutra', cell_id= 0x1701, n_id_cell=0x11, dl_earfcn= 100, tac=0x101), # CELL1 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='eutra', cell_id= 0x1702, n_id_cell=0x12, dl_earfcn=40200, tac=0x102), # CELL2
dict(rat='nr', cell_id= 0x03), # CELL3 dict(rat='nr', cell_id= 3), # CELL3
] + t.ho_inter, ] + t.ho_inter,
}, },
]) ])
# XXX SDR driver in all modes # ---- RU mixins to be used with RFTestCase4 ----
class TestENB_SDR(ENBTestCase):
# SDR4 is mixin to verify SDR driver wrt all LTE/NR x FDD/TDD modes.
class SDR4:
@classmethod @classmethod
def RUcfg(cls, i): def RUcfg(cls, i):
return { return {
'ru_type': 'sdr', 'ru_type': 'sdr',
'ru_link_type': 'sdr', 'ru_link_type': 'sdr',
'sdr_dev_list': [2*i,2*i+1], 'sdr_dev_list': [2*i,2*i+1],
'n_antenna_dl': 4,
'n_antenna_ul': 2,
} }
# radio units configuration # radio units configuration
def test_enb_conf_ru(t): def test_rf_cfg_ru(t):
rf_driver = t.enb_cfg['rf_driver'] assertMatch(t, t.rf_cfg['rf_driver'], dict(
t.assertEqual(rf_driver['args'], args='dev0=/dev/sdr2,dev1=/dev/sdr3,dev2=/dev/sdr4,dev3=/dev/sdr5,' +
'dev0=/dev/sdr2,dev1=/dev/sdr3,dev2=/dev/sdr4,dev3=/dev/sdr5,' + 'dev4=/dev/sdr6,dev5=/dev/sdr7,dev6=/dev/sdr8,dev7=/dev/sdr9',
'dev4=/dev/sdr6,dev5=/dev/sdr7,dev6=/dev/sdr8,dev7=/dev/sdr9') cpri_mapping=NO,
cpri_mult=NO,
# XXX -> generic ? XXX no (for cpri case it is all 0 here) cpri_rx_delay=NO,
t.assertEqual(t.enb_cfg['tx_gain'], [11]*4 + [12]*4 + [13]*4 + [14]*4) cpri_tx_delay=NO,
t.assertEqual(t.enb_cfg['rx_gain'], [21]*2 + [22]*2 + [23]*2 + [24]*2) cpri_tx_dbm=NO,
))
# TestENB_Lopcomm verifies enb wrt Lopcomm driver in all LTE/NR x FDD/TDD modes # Lopcomm4 is mixin to verify Lopcomm driver wrt all LTE/NR x FDD/TDD modes.
class TestENB_Lopcomm(ENBTestCase): class Lopcomm4:
@classmethod @classmethod
def RUcfg(cls, i): def RUcfg(cls, i):
return { return {
...@@ -388,177 +449,263 @@ class TestENB_Lopcomm(ENBTestCase): ...@@ -388,177 +449,263 @@ class TestENB_Lopcomm(ENBTestCase):
'mac_addr': '00:0A:45:00:00:%02x' % i, '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 @classmethod
def requestAllShared(cls, imain): def RUcfg(cls, i):
super().requestAllShared(imain)
# Lopcomm x {4t,4f,5t,5f}
def LO(i):
return { return {
'ru_type': 'lopcomm', 'ru_type': 'sunwave',
'ru_link_type': 'cpri', 'ru_link_type': 'cpri',
'cpri_link': { 'cpri_link': {
'sdr_dev': 0, 'sdr_dev': 1,
'sfp_port': 1 + i, 'sfp_port': i,
'mult': 4, 'mult': 5,
'mapping': 'hw', 'mapping': 'bf1',
'rx_delay': 25, 'rx_delay': 140+i,
'tx_delay': 14, 'tx_delay': 150+i,
'tx_dbm': 63 'tx_dbm': 160+i
}, },
'mac_addr': '00:0A:45:00:00:%02x' % i, 'mac_addr': '00:FA:FE: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),
} }
}
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 ----
""" # UEsimTestCase4 provides base class for unit-testing UEsim service.
class TestUELTEParameters(ORSTestCase): # XXX adjust #
@classmethod # It is similar to ENBTestCase4 but configures UE cells instead of eNB cells.
def getInstanceParameterDict(cls): class UEsimTestCase4(RFTestCase4):
return {'_': json.dumps(param_dict)}
@classmethod @classmethod
def getInstanceSoftwareType(cls): def getInstanceSoftwareType(cls):
return "ue-lte" return "ue"
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)}
@classmethod @classmethod
def getInstanceSoftwareType(cls): def setUpClass(cls):
return "ue-nr" super().setUpClass()
def test_ue_nr_conf(self): cls.ue_cfg = cls.rf_cfg = yamlpp_load(cls.ipath('etc/ue.cfg'))
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):
@classmethod @classmethod
def getInstanceParameterDict(cls): def getInstanceParameterDict(cls):
return {'_': json.dumps({'testing': True})} return {'_': json.dumps({
'testing': True,
})}
@classmethod @classmethod
def getInstanceSoftwareType(cls): def CELLcfg(cls, i):
return "ue" return CUE
def test_monitor_gadget_url(self): @classmethod
test_monitor_gadget_url(self) 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 ---- # ---- misc ----
...@@ -597,7 +744,6 @@ def _matchCollect(v, vok): ...@@ -597,7 +744,6 @@ def _matchCollect(v, vok):
if type(v) is dict: if type(v) is dict:
v_ = {} v_ = {}
for k in vok: for k in vok:
#v_[k] = v.get(k, NO)
v_[k] = _matchCollect(v.get(k, NO), vok[k]) v_[k] = _matchCollect(v.get(k, NO), vok[k])
return v_ return v_
if type(v) is list: if type(v) is list:
...@@ -621,5 +767,51 @@ def _matchCollect(v, vok): ...@@ -621,5 +767,51 @@ def _matchCollect(v, vok):
assert type(v) is not tuple, v assert type(v) is not tuple, v
return 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 @@ ...@@ -3,20 +3,29 @@
(cd .. && /usr/bin/python3 ../../update-hash) (cd .. && /usr/bin/python3 ../../update-hash)
export SLAPOS_TEST_DEBUG=1 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_CHECK=1
export SLAPOS_TEST_SKIP_SOFTWARE_REBUILD=1 export SLAPOS_TEST_SKIP_SOFTWARE_REBUILD=0
rm -rf snapshot rm -rf snapshot
mkdir snapshot mkdir snapshot
export SLAPOS_TEST_LOG_DIRECTORY=`pwd`/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 TestENBParameters
#time ../k/kpython_for_test -m unittest discover -vf -k NBParameters #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 CoreNetwork
#time ../k/kpython_for_test -m unittest discover -vf -k MonitorGadget #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 -k SimCard
#time ../k/kpython_for_test -m unittest discover -vf #time ../k/kpython_for_test -m unittest discover -vf -k TestENB_
#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_SDR
#time ../k/kpython_for_test -m unittest discover -vf -k TestENB_Lopcomm #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 @@ ...@@ -12,8 +12,7 @@
"dl_nr_arfcn", "dl_nr_arfcn",
"bandwidth", "bandwidth",
"nr_band", "nr_band"
"ssb_nr_arfcn"
], ],
"properties": { "properties": {
......
...@@ -416,6 +416,7 @@ ptyprocess = 0.6.0 ...@@ -416,6 +416,7 @@ ptyprocess = 0.6.0
psycopg2 = 2.8.6 psycopg2 = 2.8.6
paho-mqtt = 1.5.0 paho-mqtt = 1.5.0
pcpp = 1.30 pcpp = 1.30
xmltodict = 0.13.0
# Patched eggs # Patched eggs
PyPDF2 = 1.26.0+SlapOSPatched001 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