[ovs-dev] [PATCH ovn v2 05/10] lflow-cache: Add unit tests.
Numan Siddique
numans at ovn.org
Tue Feb 9 05:59:07 UTC 2021
On Thu, Feb 4, 2021 at 6:56 PM Dumitru Ceara <dceara at redhat.com> wrote:
>
> Signed-off-by: Dumitru Ceara <dceara at redhat.com>
Acked-by: Numan Siddique <numans at ovn.org>
Numan
> ---
> controller/test-lflow-cache.c | 224 +++++++++++++++++++++++++++++++++++
> controller/test-ofctrl-seqno.c | 18 ---
> tests/automake.mk | 8 +
> tests/ovn-lflow-cache.at | 257 ++++++++++++++++++++++++++++++++++++++++
> tests/ovn.at | 68 +++++++++++
> tests/test-utils.c | 49 ++++++++
> tests/test-utils.h | 26 ++++
> tests/testsuite.at | 1
> 8 files changed, 633 insertions(+), 18 deletions(-)
> create mode 100644 controller/test-lflow-cache.c
> create mode 100644 tests/ovn-lflow-cache.at
> create mode 100644 tests/test-utils.c
> create mode 100644 tests/test-utils.h
>
> diff --git a/controller/test-lflow-cache.c b/controller/test-lflow-cache.c
> new file mode 100644
> index 0000000..d6e962e
> --- /dev/null
> +++ b/controller/test-lflow-cache.c
> @@ -0,0 +1,224 @@
> +/* Copyright (c) 2021, Red Hat, Inc.
> + *
> + * Licensed under the Apache License, Version 2.0 (the "License");
> + * you may not use this file except in compliance with the License.
> + * You may obtain a copy of the License at:
> + *
> + * http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing, software
> + * distributed under the License is distributed on an "AS IS" BASIS,
> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> + * See the License for the specific language governing permissions and
> + * limitations under the License.
> + */
> +
> +#include <config.h>
> +
> +#include "ovn/expr.h"
> +#include "ovn-sb-idl.h"
> +#include "tests/ovstest.h"
> +#include "tests/test-utils.h"
> +#include "util.h"
> +
> +#include "lflow-cache.h"
> +
> +static void
> +test_lflow_cache_add__(struct lflow_cache *lc, const char *op_type,
> + const struct sbrec_logical_flow *lflow,
> + unsigned int conj_id_ofs,
> + struct expr *e)
> +{
> + printf("ADD %s:\n", op_type);
> + printf(" conj-id-ofs: %u\n", conj_id_ofs);
> +
> + if (!strcmp(op_type, "conj-id")) {
> + lflow_cache_add_conj_id(lc, lflow, conj_id_ofs);
> + } else if (!strcmp(op_type, "expr")) {
> + lflow_cache_add_expr(lc, lflow, conj_id_ofs, expr_clone(e));
> + } else if (!strcmp(op_type, "matches")) {
> + struct hmap *matches = xmalloc(sizeof *matches);
> + ovs_assert(expr_to_matches(e, NULL, NULL, matches) == 0);
> + ovs_assert(hmap_count(matches) == 1);
> + lflow_cache_add_matches(lc, lflow, matches);
> + } else {
> + OVS_NOT_REACHED();
> + }
> +}
> +
> +static void
> +test_lflow_cache_lookup__(struct lflow_cache *lc,
> + const struct sbrec_logical_flow *lflow)
> +{
> + struct lflow_cache_value *lcv = lflow_cache_get(lc, lflow);
> +
> + printf("LOOKUP:\n");
> + if (!lcv) {
> + printf(" not found\n");
> + return;
> + }
> +
> + printf(" conj_id_ofs: %"PRIu32"\n", lcv->conj_id_ofs);
> + switch (lcv->type) {
> + case LCACHE_T_CONJ_ID:
> + printf(" type: conj-id\n");
> + break;
> + case LCACHE_T_EXPR:
> + printf(" type: expr\n");
> + break;
> + case LCACHE_T_MATCHES:
> + printf(" type: matches\n");
> + break;
> + case LCACHE_T_NONE:
> + OVS_NOT_REACHED();
> + break;
> + }
> +}
> +
> +static void
> +test_lflow_cache_delete__(struct lflow_cache *lc,
> + const struct sbrec_logical_flow *lflow)
> +{
> + printf("DELETE\n");
> + lflow_cache_delete(lc, lflow);
> +}
> +
> +static void
> +test_lflow_cache_stats__(struct lflow_cache *lc)
> +{
> + struct lflow_cache_stats *lcs = lflow_cache_get_stats(lc);
> +
> + if (!lcs) {
> + return;
> + }
> + printf("Enabled: %s\n", lflow_cache_is_enabled(lc) ? "true" : "false");
> + for (size_t i = 0; i < LCACHE_T_MAX; i++) {
> + printf(" %s: %"PRIuSIZE"\n", lflow_cache_type_names[i],
> + lcs->n_entries[i]);
> + }
> + free(lcs);
> +}
> +
> +static void
> +test_lflow_cache_operations(struct ovs_cmdl_context *ctx)
> +{
> + struct lflow_cache *lc = lflow_cache_create();
> + struct expr *e = expr_create_boolean(true);
> + bool enabled = !strcmp(ctx->argv[1], "true");
> + unsigned int shift = 2;
> + unsigned int n_ops;
> +
> + lflow_cache_enable(lc, enabled);
> + test_lflow_cache_stats__(lc);
> +
> + if (!test_read_uint_value(ctx, shift++, "n_ops", &n_ops)) {
> + goto done;
> + }
> +
> + for (unsigned int i = 0; i < n_ops; i++) {
> + const char *op = test_read_value(ctx, shift++, "op");
> +
> + if (!op) {
> + goto done;
> + }
> +
> + struct sbrec_logical_flow lflow;
> + uuid_generate(&lflow.header_.uuid);
> +
> + if (!strcmp(op, "add")) {
> + const char *op_type = test_read_value(ctx, shift++, "op_type");
> + if (!op_type) {
> + goto done;
> + }
> +
> + unsigned int conj_id_ofs;
> + if (!test_read_uint_value(ctx, shift++, "conj-id-ofs",
> + &conj_id_ofs)) {
> + goto done;
> + }
> +
> + test_lflow_cache_add__(lc, op_type, &lflow, conj_id_ofs, e);
> + test_lflow_cache_lookup__(lc, &lflow);
> + } else if (!strcmp(op, "add-del")) {
> + const char *op_type = test_read_value(ctx, shift++, "op_type");
> + if (!op_type) {
> + goto done;
> + }
> +
> + unsigned int conj_id_ofs;
> + if (!test_read_uint_value(ctx, shift++, "conj-id-ofs",
> + &conj_id_ofs)) {
> + goto done;
> + }
> +
> + test_lflow_cache_add__(lc, op_type, &lflow, conj_id_ofs, e);
> + test_lflow_cache_lookup__(lc, &lflow);
> + test_lflow_cache_delete__(lc, &lflow);
> + test_lflow_cache_lookup__(lc, &lflow);
> + } else if (!strcmp(op, "enable")) {
> + printf("ENABLE\n");
> + lflow_cache_enable(lc, true);
> + } else if (!strcmp(op, "disable")) {
> + printf("DISABLE\n");
> + lflow_cache_enable(lc, false);
> + } else if (!strcmp(op, "flush")) {
> + printf("FLUSH\n");
> + lflow_cache_flush(lc);
> + } else {
> + OVS_NOT_REACHED();
> + }
> + test_lflow_cache_stats__(lc);
> + }
> +done:
> + lflow_cache_destroy(lc);
> + expr_destroy(e);
> +}
> +
> +static void
> +test_lflow_cache_negative(struct ovs_cmdl_context *ctx OVS_UNUSED)
> +{
> + lflow_cache_flush(NULL);
> + lflow_cache_destroy(NULL);
> + lflow_cache_enable(NULL, true);
> + ovs_assert(!lflow_cache_is_enabled(NULL));
> + ovs_assert(!lflow_cache_get_stats(NULL));
> +
> + struct lflow_cache *lcs[] = {
> + NULL,
> + lflow_cache_create(),
> + };
> +
> + for (size_t i = 0; i < ARRAY_SIZE(lcs); i++) {
> + struct expr *e = expr_create_boolean(true);
> + struct hmap *matches = xmalloc(sizeof *matches);
> +
> + ovs_assert(expr_to_matches(e, NULL, NULL, matches) == 0);
> + ovs_assert(hmap_count(matches) == 1);
> +
> + lflow_cache_add_conj_id(lcs[i], NULL, 0);
> + lflow_cache_add_expr(lcs[i], NULL, 0, NULL);
> + lflow_cache_add_expr(lcs[i], NULL, 0, e);
> + lflow_cache_add_matches(lcs[i], NULL, NULL);
> + lflow_cache_add_matches(lcs[i], NULL, matches);
> + lflow_cache_destroy(lcs[i]);
> + }
> +}
> +
> +static void
> +test_lflow_cache_main(int argc, char *argv[])
> +{
> + set_program_name(argv[0]);
> + static const struct ovs_cmdl_command commands[] = {
> + {"lflow_cache_operations", NULL, 3, INT_MAX,
> + test_lflow_cache_operations, OVS_RO},
> + {"lflow_cache_negative", NULL, 0, 0,
> + test_lflow_cache_negative, OVS_RO},
> + {NULL, NULL, 0, 0, NULL, OVS_RO},
> + };
> + struct ovs_cmdl_context ctx;
> + ctx.argc = argc - 1;
> + ctx.argv = argv + 1;
> + ovs_cmdl_run_command(&ctx, commands);
> +}
> +
> +OVSTEST_REGISTER("test-lflow-cache", test_lflow_cache_main);
> diff --git a/controller/test-ofctrl-seqno.c b/controller/test-ofctrl-seqno.c
> index fce88d4..b96da9d 100644
> --- a/controller/test-ofctrl-seqno.c
> +++ b/controller/test-ofctrl-seqno.c
> @@ -16,6 +16,7 @@
> #include <config.h>
>
> #include "tests/ovstest.h"
> +#include "tests/test-utils.h"
> #include "sort.h"
> #include "util.h"
>
> @@ -27,23 +28,6 @@ test_init(void)
> ofctrl_seqno_init();
> }
>
> -static bool
> -test_read_uint_value(struct ovs_cmdl_context *ctx, unsigned int index,
> - const char *descr, unsigned int *result)
> -{
> - if (index >= ctx->argc) {
> - fprintf(stderr, "Missing %s argument\n", descr);
> - return false;
> - }
> -
> - const char *arg = ctx->argv[index];
> - if (!str_to_uint(arg, 10, result)) {
> - fprintf(stderr, "Invalid %s: %s\n", descr, arg);
> - return false;
> - }
> - return true;
> -}
> -
> static int
> test_seqno_compare(size_t a, size_t b, void *values_)
> {
> diff --git a/tests/automake.mk b/tests/automake.mk
> index 282d1b1..df6d0a2 100644
> --- a/tests/automake.mk
> +++ b/tests/automake.mk
> @@ -33,7 +33,8 @@ TESTSUITE_AT = \
> tests/ovn-macros.at \
> tests/ovn-performance.at \
> tests/ovn-ofctrl-seqno.at \
> - tests/ovn-ipam.at
> + tests/ovn-ipam.at \
> + tests/ovn-lflow-cache.at
>
> SYSTEM_KMOD_TESTSUITE_AT = \
> tests/system-common-macros.at \
> @@ -207,8 +208,13 @@ noinst_PROGRAMS += tests/ovstest
> tests_ovstest_SOURCES = \
> tests/ovstest.c \
> tests/ovstest.h \
> + tests/test-utils.c \
> + tests/test-utils.h \
> tests/test-ovn.c \
> + controller/test-lflow-cache.c \
> controller/test-ofctrl-seqno.c \
> + controller/lflow-cache.c \
> + controller/lflow-cache.h \
> controller/ofctrl-seqno.c \
> controller/ofctrl-seqno.h \
> northd/test-ipam.c \
> diff --git a/tests/ovn-lflow-cache.at b/tests/ovn-lflow-cache.at
> new file mode 100644
> index 0000000..f7e8959
> --- /dev/null
> +++ b/tests/ovn-lflow-cache.at
> @@ -0,0 +1,257 @@
> +#
> +# Unit tests for the controller/lflow-cache.c module.
> +#
> +AT_BANNER([OVN unit tests - lflow-cache])
> +
> +AT_SETUP([ovn -- unit test -- lflow-cache single add/lookup])
> +AT_CHECK(
> + [ovstest test-lflow-cache lflow_cache_operations \
> + true 3 \
> + add conj-id 1 \
> + add expr 2 \
> + add matches 3],
> + [0], [dnl
> +Enabled: true
> + cache-conj-id: 0
> + cache-expr: 0
> + cache-matches: 0
> +ADD conj-id:
> + conj-id-ofs: 1
> +LOOKUP:
> + conj_id_ofs: 1
> + type: conj-id
> +Enabled: true
> + cache-conj-id: 1
> + cache-expr: 0
> + cache-matches: 0
> +ADD expr:
> + conj-id-ofs: 2
> +LOOKUP:
> + conj_id_ofs: 2
> + type: expr
> +Enabled: true
> + cache-conj-id: 1
> + cache-expr: 1
> + cache-matches: 0
> +ADD matches:
> + conj-id-ofs: 3
> +LOOKUP:
> + conj_id_ofs: 0
> + type: matches
> +Enabled: true
> + cache-conj-id: 1
> + cache-expr: 1
> + cache-matches: 1
> +])
> +AT_CLEANUP
> +
> +AT_SETUP([ovn -- unit test -- lflow-cache single add/lookup/del])
> +AT_CHECK(
> + [ovstest test-lflow-cache lflow_cache_operations \
> + true 3 \
> + add-del conj-id 1 \
> + add-del expr 2 \
> + add-del matches 3],
> + [0], [dnl
> +Enabled: true
> + cache-conj-id: 0
> + cache-expr: 0
> + cache-matches: 0
> +ADD conj-id:
> + conj-id-ofs: 1
> +LOOKUP:
> + conj_id_ofs: 1
> + type: conj-id
> +DELETE
> +LOOKUP:
> + not found
> +Enabled: true
> + cache-conj-id: 0
> + cache-expr: 0
> + cache-matches: 0
> +ADD expr:
> + conj-id-ofs: 2
> +LOOKUP:
> + conj_id_ofs: 2
> + type: expr
> +DELETE
> +LOOKUP:
> + not found
> +Enabled: true
> + cache-conj-id: 0
> + cache-expr: 0
> + cache-matches: 0
> +ADD matches:
> + conj-id-ofs: 3
> +LOOKUP:
> + conj_id_ofs: 0
> + type: matches
> +DELETE
> +LOOKUP:
> + not found
> +Enabled: true
> + cache-conj-id: 0
> + cache-expr: 0
> + cache-matches: 0
> +])
> +AT_CLEANUP
> +
> +AT_SETUP([ovn -- unit test -- lflow-cache disabled single add/lookup/del])
> +AT_CHECK(
> + [ovstest test-lflow-cache lflow_cache_operations \
> + false 3 \
> + add conj-id 1 \
> + add expr 2 \
> + add matches 3],
> + [0], [dnl
> +Enabled: false
> + cache-conj-id: 0
> + cache-expr: 0
> + cache-matches: 0
> +ADD conj-id:
> + conj-id-ofs: 1
> +LOOKUP:
> + not found
> +Enabled: false
> + cache-conj-id: 0
> + cache-expr: 0
> + cache-matches: 0
> +ADD expr:
> + conj-id-ofs: 2
> +LOOKUP:
> + not found
> +Enabled: false
> + cache-conj-id: 0
> + cache-expr: 0
> + cache-matches: 0
> +ADD matches:
> + conj-id-ofs: 3
> +LOOKUP:
> + not found
> +Enabled: false
> + cache-conj-id: 0
> + cache-expr: 0
> + cache-matches: 0
> +])
> +AT_CLEANUP
> +
> +AT_SETUP([ovn -- unit test -- lflow-cache disable/enable/flush])
> +AT_CHECK(
> + [ovstest test-lflow-cache lflow_cache_operations \
> + true 12 \
> + add conj-id 1 \
> + add expr 2 \
> + add matches 3 \
> + disable \
> + add conj-id 4 \
> + add expr 5 \
> + add matches 6 \
> + enable \
> + add conj-id 7 \
> + add expr 8 \
> + add matches 9 \
> + flush],
> + [0], [dnl
> +Enabled: true
> + cache-conj-id: 0
> + cache-expr: 0
> + cache-matches: 0
> +ADD conj-id:
> + conj-id-ofs: 1
> +LOOKUP:
> + conj_id_ofs: 1
> + type: conj-id
> +Enabled: true
> + cache-conj-id: 1
> + cache-expr: 0
> + cache-matches: 0
> +ADD expr:
> + conj-id-ofs: 2
> +LOOKUP:
> + conj_id_ofs: 2
> + type: expr
> +Enabled: true
> + cache-conj-id: 1
> + cache-expr: 1
> + cache-matches: 0
> +ADD matches:
> + conj-id-ofs: 3
> +LOOKUP:
> + conj_id_ofs: 0
> + type: matches
> +Enabled: true
> + cache-conj-id: 1
> + cache-expr: 1
> + cache-matches: 1
> +DISABLE
> +Enabled: false
> + cache-conj-id: 0
> + cache-expr: 0
> + cache-matches: 0
> +ADD conj-id:
> + conj-id-ofs: 4
> +LOOKUP:
> + not found
> +Enabled: false
> + cache-conj-id: 0
> + cache-expr: 0
> + cache-matches: 0
> +ADD expr:
> + conj-id-ofs: 5
> +LOOKUP:
> + not found
> +Enabled: false
> + cache-conj-id: 0
> + cache-expr: 0
> + cache-matches: 0
> +ADD matches:
> + conj-id-ofs: 6
> +LOOKUP:
> + not found
> +Enabled: false
> + cache-conj-id: 0
> + cache-expr: 0
> + cache-matches: 0
> +ENABLE
> +Enabled: true
> + cache-conj-id: 0
> + cache-expr: 0
> + cache-matches: 0
> +ADD conj-id:
> + conj-id-ofs: 7
> +LOOKUP:
> + conj_id_ofs: 7
> + type: conj-id
> +Enabled: true
> + cache-conj-id: 1
> + cache-expr: 0
> + cache-matches: 0
> +ADD expr:
> + conj-id-ofs: 8
> +LOOKUP:
> + conj_id_ofs: 8
> + type: expr
> +Enabled: true
> + cache-conj-id: 1
> + cache-expr: 1
> + cache-matches: 0
> +ADD matches:
> + conj-id-ofs: 9
> +LOOKUP:
> + conj_id_ofs: 0
> + type: matches
> +Enabled: true
> + cache-conj-id: 1
> + cache-expr: 1
> + cache-matches: 1
> +FLUSH
> +Enabled: true
> + cache-conj-id: 0
> + cache-expr: 0
> + cache-matches: 0
> +])
> +AT_CLEANUP
> +
> +AT_SETUP([ovn -- unit test -- lflow-cache negative tests])
> +AT_CHECK([ovstest test-lflow-cache lflow_cache_negative], [0], [])
> +AT_CLEANUP
> diff --git a/tests/ovn.at b/tests/ovn.at
> index 4a75acc..0e114cf 100644
> --- a/tests/ovn.at
> +++ b/tests/ovn.at
> @@ -22235,6 +22235,74 @@ OVN_CLEANUP([hv1])
>
> AT_CLEANUP
>
> +AT_SETUP([ovn -- lflow cache operations])
> +ovn_start
> +net_add n1
> +sim_add hv1
> +
> +as hv1
> +ovs-vsctl add-br br-phys
> +ovn_attach n1 br-phys 192.168.0.1
> +
> +as hv1
> +ovs-vsctl -- add-port br-int hv1-vif1 \
> + -- set interface hv1-vif1 external-ids:iface-id=lsp1 \
> + -- add-port br-int hv1-vif2 \
> + -- set interface hv1-vif2 external-ids:iface-id=lsp2
> +
> +ovn-nbctl ls-add ls1 \
> + -- lsp-add ls1 lsp1 \
> + -- lsp-add ls1 lsp2 \
> + -- pg-add pg1 lsp1 lsp2 \
> + -- create Address_Set name=as1 addresses=\"10.0.0.1\",\"10.0.0.2\"
> +check ovn-nbctl --wait=hv sync
> +wait_for_ports_up lsp1 lsp2
> +
> +get_cache_count () {
> + local cache_name=$1
> + as hv1 ovn-appctl -t ovn-controller lflow-cache/show-stats | grep ${cache_name} | awk '{ print $3 }'
> +}
> +
> +AS_BOX([Check matches caching])
> +conj_id_cnt=$(get_cache_count cache-conj-id)
> +expr_cnt=$(get_cache_count cache-expr)
> +matches_cnt=$(get_cache_count cache-matches)
> +
> +check ovn-nbctl acl-add ls1 from-lport 1 '1' drop
> +check ovn-nbctl --wait=hv sync
> +
> +AT_CHECK([test "$conj_id_cnt" = "$(get_cache_count cache-conj-id)"], [0], [])
> +AT_CHECK([test "$expr_cnt" = "$(get_cache_count cache-expr)"], [0], [])
> +AT_CHECK([test "$(($matches_cnt + 1))" = "$(get_cache_count cache-matches)"], [0], [])
> +
> +AS_BOX([Check expr caching for is_chassis_resident() matches])
> +conj_id_cnt=$(get_cache_count cache-conj-id)
> +expr_cnt=$(get_cache_count cache-expr)
> +matches_cnt=$(get_cache_count cache-matches)
> +
> +check ovn-nbctl acl-add ls1 from-lport 1 'is_chassis_resident("lsp1")' drop
> +check ovn-nbctl --wait=hv sync
> +
> +AT_CHECK([test "$conj_id_cnt" = "$(get_cache_count cache-conj-id)"], [0], [])
> +AT_CHECK([test "$(($expr_cnt + 1))" = "$(get_cache_count cache-expr)"], [0], [])
> +AT_CHECK([test "$matches_cnt" = "$(get_cache_count cache-matches)"], [0], [])
> +
> +AS_BOX([Check conj-id caching for conjunctive port group/address set matches])
> +conj_id_cnt=$(get_cache_count cache-conj-id)
> +expr_cnt=$(get_cache_count cache-expr)
> +matches_cnt=$(get_cache_count cache-matches)
> +
> +check ovn-nbctl acl-add ls1 from-lport 1 'inport == @pg1 && outport == @pg1 && is_chassis_resident("lsp1")' drop
> +check ovn-nbctl acl-add ls1 from-lport 1 'ip4.src == $as1 && ip4.dst == $as1 && is_chassis_resident("lsp1")' drop
> +check ovn-nbctl --wait=hv sync
> +
> +AT_CHECK([test "$(($conj_id_cnt + 2))" = "$(get_cache_count cache-conj-id)"], [0], [])
> +AT_CHECK([test "$expr_cnt" = "$(get_cache_count cache-expr)"], [0], [])
> +AT_CHECK([test "$matches_cnt" = "$(get_cache_count cache-matches)"], [0], [])
> +
> +OVN_CLEANUP([hv1])
> +AT_CLEANUP
> +
> AT_SETUP([ovn -- Delete Port_Binding and OVS port Incremental Processing])
> ovn_start
>
> diff --git a/tests/test-utils.c b/tests/test-utils.c
> new file mode 100644
> index 0000000..6a3b198
> --- /dev/null
> +++ b/tests/test-utils.c
> @@ -0,0 +1,49 @@
> +/* Copyright (c) 2021, Red Hat, Inc.
> + *
> + * Licensed under the Apache License, Version 2.0 (the "License");
> + * you may not use this file except in compliance with the License.
> + * You may obtain a copy of the License at:
> + *
> + * http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing, software
> + * distributed under the License is distributed on an "AS IS" BASIS,
> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> + * See the License for the specific language governing permissions and
> + * limitations under the License.
> + */
> +
> +#include <config.h>
> +
> +#include "test-utils.h"
> +
> +#include "util.h"
> +
> +bool
> +test_read_uint_value(struct ovs_cmdl_context *ctx, unsigned int index,
> + const char *descr, unsigned int *result)
> +{
> + if (index >= ctx->argc) {
> + fprintf(stderr, "Missing %s argument\n", descr);
> + return false;
> + }
> +
> + const char *arg = ctx->argv[index];
> + if (!str_to_uint(arg, 10, result)) {
> + fprintf(stderr, "Invalid %s: %s\n", descr, arg);
> + return false;
> + }
> + return true;
> +}
> +
> +const char *
> +test_read_value(struct ovs_cmdl_context *ctx, unsigned int index,
> + const char *descr)
> +{
> + if (index >= ctx->argc) {
> + fprintf(stderr, "Missing %s argument\n", descr);
> + return NULL;
> + }
> +
> + return ctx->argv[index];
> +}
> diff --git a/tests/test-utils.h b/tests/test-utils.h
> new file mode 100644
> index 0000000..721032f
> --- /dev/null
> +++ b/tests/test-utils.h
> @@ -0,0 +1,26 @@
> +/* Copyright (c) 2021, Red Hat, Inc.
> + *
> + * Licensed under the Apache License, Version 2.0 (the "License");
> + * you may not use this file except in compliance with the License.
> + * You may obtain a copy of the License at:
> + *
> + * http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing, software
> + * distributed under the License is distributed on an "AS IS" BASIS,
> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> + * See the License for the specific language governing permissions and
> + * limitations under the License.
> + */
> +
> +#ifndef TEST_UTILS_H
> +#define TEST_UTILS_H 1
> +
> +#include "ovstest.h"
> +
> +bool test_read_uint_value(struct ovs_cmdl_context *ctx, unsigned int index,
> + const char *descr, unsigned int *result);
> +const char *test_read_value(struct ovs_cmdl_context *ctx, unsigned int index,
> + const char *descr);
> +
> +#endif /* tests/test-utils.h */
> diff --git a/tests/testsuite.at b/tests/testsuite.at
> index 6253d11..35908ad 100644
> --- a/tests/testsuite.at
> +++ b/tests/testsuite.at
> @@ -27,6 +27,7 @@ m4_include([tests/ovn.at])
> m4_include([tests/ovn-performance.at])
> m4_include([tests/ovn-northd.at])
> m4_include([tests/ovn-nbctl.at])
> +m4_include([tests/ovn-lflow-cache.at])
> m4_include([tests/ovn-ofctrl-seqno.at])
> m4_include([tests/ovn-sbctl.at])
> m4_include([tests/ovn-ic-nbctl.at])
>
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
More information about the dev
mailing list