diff --git a/.gitignore b/.gitignore index 554879a..4ae71da 100644 --- a/.gitignore +++ b/.gitignore @@ -36,6 +36,7 @@ tests/alloc/AllocTest tests/rlcmac/RLCMACTest tests/tbf/TbfTest tests/types/TypesTest +tests/ms/MsTest tests/emu/pcu_emu tests/testsuite tests/testsuite.log diff --git a/src/Makefile.am b/src/Makefile.am index 210774c..8a422f6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -37,6 +37,7 @@ libgprs_la_SOURCES = \ gprs_rlcmac_sched.cpp \ gprs_rlcmac_meas.cpp \ gprs_rlcmac_ts_alloc.cpp \ + gprs_ms.cpp \ gsm_timer.cpp \ bitvector.cpp \ pcu_l1_if.cpp \ @@ -77,6 +78,7 @@ noinst_HEADERS = \ gsm_rlcmac.h \ gprs_bssgp_pcu.h \ gprs_rlcmac.h \ + gprs_ms.h \ pcuif_proto.h \ pcu_l1_if.h \ gsm_timer.h \ diff --git a/src/gprs_ms.cpp b/src/gprs_ms.cpp new file mode 100644 index 0000000..db29d20 --- /dev/null +++ b/src/gprs_ms.cpp @@ -0,0 +1,182 @@ +/* gprs_ms.cpp + * + * Copyright (C) 2015 by Sysmocom s.f.m.c. GmbH + * Author: Jacob Erlbeck + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +#include "gprs_ms.h" + +#include "tbf.h" +#include "gprs_debug.h" + +extern "C" { + #include + #include +} + +extern void *tall_pcu_ctx; + +struct GprsMsDefaultCallback: public GprsMs::Callback { + virtual void ms_idle(class GprsMs *ms) { + delete ms; + } + virtual void ms_active(class GprsMs *) {} +}; + +static GprsMsDefaultCallback gprs_default_cb; + + +GprsMs::Guard::Guard(GprsMs *ms) : m_ms(ms) +{ + if (m_ms) + m_ms->ref(); +} + +GprsMs::Guard::~Guard() +{ + if (m_ms) + m_ms->unref(); +} + +GprsMs::GprsMs(uint32_t tlli) : + m_cb(&gprs_default_cb), + m_ul_tbf(NULL), + m_dl_tbf(NULL), + m_tlli(tlli), + m_is_idle(true), + m_ref(0) +{ + LOGP(DRLCMAC, LOGL_INFO, "Creating MS object, TLLI = 0x%08x\n", tlli); +} + +GprsMs::~GprsMs() +{ + LOGP(DRLCMAC, LOGL_INFO, "Destroying MS object, TLLI = 0x%08x\n", tlli()); +} + +void* GprsMs::operator new(size_t size) +{ + static void *tall_ms_ctx = NULL; + if (!tall_ms_ctx) + tall_ms_ctx = talloc_named_const(tall_pcu_ctx, 0, __PRETTY_FUNCTION__); + + return talloc_size(tall_ms_ctx, size); +} + +void GprsMs::operator delete(void* p) +{ + talloc_free(p); +} + +void GprsMs::ref() +{ + m_ref += 1; +} + +void GprsMs::unref() +{ + OSMO_ASSERT(m_ref >= 0); + m_ref -= 1; + if (m_ref == 0) + update_status(); +} + +void GprsMs::attach_tbf(struct gprs_rlcmac_tbf *tbf) +{ + if (tbf->direction == GPRS_RLCMAC_DL_TBF) + attach_dl_tbf(static_cast(tbf)); + else + attach_ul_tbf(static_cast(tbf)); +} + +void GprsMs::attach_ul_tbf(struct gprs_rlcmac_ul_tbf *tbf) +{ + if (m_ul_tbf == tbf) + return; + + LOGP(DRLCMAC, LOGL_INFO, "Attaching TBF to MS object, TLLI = 0x%08x, TBF = %s\n", + tlli(), tbf->name()); + + Guard guard(this); + + if (m_ul_tbf) + detach_tbf(m_ul_tbf); + + m_ul_tbf = tbf; +} + +void GprsMs::attach_dl_tbf(struct gprs_rlcmac_dl_tbf *tbf) +{ + if (m_dl_tbf == tbf) + return; + + LOGP(DRLCMAC, LOGL_INFO, "Attaching TBF to MS object, TLLI = 0x%08x, TBF = %s\n", + tlli(), tbf->name()); + + Guard guard(this); + + if (m_dl_tbf) + detach_tbf(m_dl_tbf); + + m_dl_tbf = tbf; +} + +void GprsMs::detach_tbf(gprs_rlcmac_tbf *tbf) +{ + if (m_ul_tbf && tbf == static_cast(m_ul_tbf)) + m_ul_tbf = NULL; + else if (m_dl_tbf && tbf == static_cast(m_dl_tbf)) + m_dl_tbf = NULL; + else + return; + + LOGP(DRLCMAC, LOGL_INFO, "Detaching TBF from MS object, TLLI = 0x%08x, TBF = %s\n", + tlli(), tbf->name()); + + update_status(); +} + +void GprsMs::update_status() +{ + if (m_ref > 0) + return; + + if (is_idle() && !m_is_idle) { + m_is_idle = true; + m_cb->ms_idle(this); + /* this can be deleted by now, do not access it */ + return; + } + + if (!is_idle() && m_is_idle) { + m_is_idle = false; + m_cb->ms_active(this); + } +} + +void GprsMs::set_tlli(uint32_t tlli) +{ + if (tlli == m_tlli) + return; + + LOGP(DRLCMAC, LOGL_INFO, + "Modifying MS object, TLLI: 0x%08x -> 0x%08x\n", + m_tlli, tlli); + + m_tlli = tlli; +} diff --git a/src/gprs_ms.h b/src/gprs_ms.h new file mode 100644 index 0000000..a59fc5b --- /dev/null +++ b/src/gprs_ms.h @@ -0,0 +1,79 @@ +/* gprs_ms.h + * + * Copyright (C) 2015 by Sysmocom s.f.m.c. GmbH + * Author: Jacob Erlbeck + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#pragma once + +struct gprs_rlcmac_tbf; +struct gprs_rlcmac_dl_tbf; +struct gprs_rlcmac_ul_tbf; + +#include +#include + +class GprsMs { +public: + struct Callback { + virtual void ms_idle(class GprsMs *) = 0; + virtual void ms_active(class GprsMs *) = 0; + }; + + class Guard { + public: + Guard(GprsMs *ms); + ~Guard(); + + private: + GprsMs * const m_ms; + }; + + GprsMs(uint32_t tlli); + ~GprsMs(); + + void set_callback(Callback *cb) {m_cb = cb;} + + gprs_rlcmac_ul_tbf *ul_tbf() const {return m_ul_tbf;} + gprs_rlcmac_dl_tbf *dl_tbf() const {return m_dl_tbf;} + uint32_t tlli() const {return m_tlli;} + void set_tlli(uint32_t tlli); + + void attach_tbf(gprs_rlcmac_tbf *tbf); + void attach_ul_tbf(gprs_rlcmac_ul_tbf *tbf); + void attach_dl_tbf(gprs_rlcmac_dl_tbf *tbf); + + void detach_tbf(gprs_rlcmac_tbf *tbf); + + bool is_idle() const {return !m_ul_tbf && !m_dl_tbf && !m_ref;} + + void* operator new(size_t num); + void operator delete(void* p); + +protected: + void update_status(); + void ref(); + void unref(); + +private: + Callback * m_cb; + gprs_rlcmac_ul_tbf *m_ul_tbf; + gprs_rlcmac_dl_tbf *m_dl_tbf; + uint32_t m_tlli; + bool m_is_idle; + int m_ref; +}; diff --git a/tests/Makefile.am b/tests/Makefile.am index 683a64c..7b2d32d 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,6 +1,6 @@ AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGB_CFLAGS) $(LIBOSMOGSM_CFLAGS) -I$(top_srcdir)/src/ -check_PROGRAMS = rlcmac/RLCMACTest alloc/AllocTest tbf/TbfTest types/TypesTest +check_PROGRAMS = rlcmac/RLCMACTest alloc/AllocTest tbf/TbfTest types/TypesTest ms/MsTest noinst_PROGRAMS = emu/pcu_emu rlcmac_RLCMACTest_SOURCES = rlcmac/RLCMACTest.cpp @@ -43,6 +43,16 @@ types_TypesTest_LDADD = \ $(LIBOSMOCORE_LIBS) \ $(COMMON_LA) +ms_MsTest_SOURCES = ms/MsTest.cpp +ms_MsTest_LDADD = \ + $(top_builddir)/src/libgprs.la \ + $(LIBOSMOGB_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(COMMON_LA) + +ms_MsTest_LDFLAGS = \ + -Wl,-u,bssgp_prim_cb # The `:;' works around a Bash 3.2 bug when the output is not writeable. $(srcdir)/package.m4: $(top_srcdir)/configure.ac @@ -67,7 +77,8 @@ EXTRA_DIST = \ rlcmac/RLCMACTest.ok rlcmac/RLCMACTest.err \ alloc/AllocTest.ok alloc/AllocTest.err \ tbf/TbfTest.ok tbf/TbfTest.err \ - types/TypesTest.ok types/TypesTest.err + types/TypesTest.ok types/TypesTest.err \ + ms/MsTest.ok ms/MsTest.err DISTCLEANFILES = atconfig diff --git a/tests/ms/MsTest.cpp b/tests/ms/MsTest.cpp new file mode 100644 index 0000000..59c92b3 --- /dev/null +++ b/tests/ms/MsTest.cpp @@ -0,0 +1,283 @@ +/* + * MsTest.cpp + * + * Copyright (C) 2015 by Sysmocom s.f.m.c. GmbH + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include "tbf.h" +#include "gprs_debug.h" +#include "gprs_ms.h" + +extern "C" { +#include "pcu_vty.h" + +#include +#include +#include +#include +#include +} + +#include + +void *tall_pcu_ctx; +int16_t spoof_mnc = 0, spoof_mcc = 0; + +static void test_ms_state() +{ + uint32_t tlli = 0xffeeddbb; + gprs_rlcmac_dl_tbf *dl_tbf; + gprs_rlcmac_ul_tbf *ul_tbf; + GprsMs *ms; + + printf("=== start %s ===\n", __func__); + + ms = new GprsMs(tlli); + OSMO_ASSERT(ms->is_idle()); + + dl_tbf = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_dl_tbf); + dl_tbf->direction = GPRS_RLCMAC_DL_TBF; + ul_tbf = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_ul_tbf); + ul_tbf->direction = GPRS_RLCMAC_UL_TBF; + + ms->attach_tbf(ul_tbf); + OSMO_ASSERT(!ms->is_idle()); + OSMO_ASSERT(ms->ul_tbf() == ul_tbf); + OSMO_ASSERT(ms->dl_tbf() == NULL); + + ms->attach_tbf(dl_tbf); + OSMO_ASSERT(!ms->is_idle()); + OSMO_ASSERT(ms->ul_tbf() == ul_tbf); + OSMO_ASSERT(ms->dl_tbf() == dl_tbf); + + ms->detach_tbf(ul_tbf); + OSMO_ASSERT(!ms->is_idle()); + OSMO_ASSERT(ms->ul_tbf() == NULL); + OSMO_ASSERT(ms->dl_tbf() == dl_tbf); + + ms->detach_tbf(dl_tbf); + /* The ms object is freed now */ + ms = NULL; + + talloc_free(dl_tbf); + talloc_free(ul_tbf); + + printf("=== end %s ===\n", __func__); +} + +static void test_ms_callback() +{ + uint32_t tlli = 0xffeeddbb; + gprs_rlcmac_dl_tbf *dl_tbf; + gprs_rlcmac_ul_tbf *ul_tbf; + GprsMs *ms; + static enum {UNKNOWN, IS_IDLE, IS_ACTIVE} last_cb = UNKNOWN; + + struct MyCallback: public GprsMs::Callback { + virtual void ms_idle(class GprsMs *ms) { + OSMO_ASSERT(ms->is_idle()); + printf(" ms_idle() was called\n"); + last_cb = IS_IDLE; + } + virtual void ms_active(class GprsMs *ms) { + OSMO_ASSERT(!ms->is_idle()); + printf(" ms_active() was called\n"); + last_cb = IS_ACTIVE; + } + } cb; + + printf("=== start %s ===\n", __func__); + + ms = new GprsMs(tlli); + ms->set_callback(&cb); + + OSMO_ASSERT(ms->is_idle()); + + dl_tbf = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_dl_tbf); + dl_tbf->direction = GPRS_RLCMAC_DL_TBF; + ul_tbf = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_ul_tbf); + ul_tbf->direction = GPRS_RLCMAC_UL_TBF; + + OSMO_ASSERT(last_cb == UNKNOWN); + + ms->attach_tbf(ul_tbf); + OSMO_ASSERT(!ms->is_idle()); + OSMO_ASSERT(ms->ul_tbf() == ul_tbf); + OSMO_ASSERT(ms->dl_tbf() == NULL); + OSMO_ASSERT(last_cb == IS_ACTIVE); + + last_cb = UNKNOWN; + + ms->attach_tbf(dl_tbf); + OSMO_ASSERT(!ms->is_idle()); + OSMO_ASSERT(ms->ul_tbf() == ul_tbf); + OSMO_ASSERT(ms->dl_tbf() == dl_tbf); + OSMO_ASSERT(last_cb == UNKNOWN); + + ms->detach_tbf(ul_tbf); + OSMO_ASSERT(!ms->is_idle()); + OSMO_ASSERT(ms->ul_tbf() == NULL); + OSMO_ASSERT(ms->dl_tbf() == dl_tbf); + OSMO_ASSERT(last_cb == UNKNOWN); + + ms->detach_tbf(dl_tbf); + OSMO_ASSERT(ms->is_idle()); + OSMO_ASSERT(ms->ul_tbf() == NULL); + OSMO_ASSERT(ms->dl_tbf() == NULL); + OSMO_ASSERT(last_cb == IS_IDLE); + + last_cb = UNKNOWN; + delete ms; + + talloc_free(dl_tbf); + talloc_free(ul_tbf); + + printf("=== end %s ===\n", __func__); +} + +static void test_ms_replace_tbf() +{ + uint32_t tlli = 0xffeeddbb; + gprs_rlcmac_dl_tbf *dl_tbf[2]; + gprs_rlcmac_ul_tbf *ul_tbf; + GprsMs *ms; + static bool was_idle; + + struct MyCallback: public GprsMs::Callback { + virtual void ms_idle(class GprsMs *ms) { + OSMO_ASSERT(ms->is_idle()); + printf(" ms_idle() was called\n"); + was_idle = true; + } + virtual void ms_active(class GprsMs *ms) { + OSMO_ASSERT(!ms->is_idle()); + printf(" ms_active() was called\n"); + } + } cb; + + printf("=== start %s ===\n", __func__); + + ms = new GprsMs(tlli); + ms->set_callback(&cb); + + OSMO_ASSERT(ms->is_idle()); + was_idle = false; + + dl_tbf[0] = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_dl_tbf); + dl_tbf[0]->direction = GPRS_RLCMAC_DL_TBF; + dl_tbf[1] = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_dl_tbf); + dl_tbf[1]->direction = GPRS_RLCMAC_DL_TBF; + ul_tbf = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_ul_tbf); + ul_tbf->direction = GPRS_RLCMAC_UL_TBF; + + ms->attach_tbf(dl_tbf[0]); + OSMO_ASSERT(!ms->is_idle()); + OSMO_ASSERT(ms->ul_tbf() == NULL); + OSMO_ASSERT(ms->dl_tbf() == dl_tbf[0]); + OSMO_ASSERT(!was_idle); + + ms->attach_tbf(dl_tbf[1]); + OSMO_ASSERT(!ms->is_idle()); + OSMO_ASSERT(ms->ul_tbf() == NULL); + OSMO_ASSERT(ms->dl_tbf() == dl_tbf[1]); + OSMO_ASSERT(!was_idle); + + ms->attach_tbf(ul_tbf); + OSMO_ASSERT(!ms->is_idle()); + OSMO_ASSERT(ms->ul_tbf() == ul_tbf); + OSMO_ASSERT(ms->dl_tbf() == dl_tbf[1]); + OSMO_ASSERT(!was_idle); + + ms->detach_tbf(ul_tbf); + OSMO_ASSERT(!ms->is_idle()); + OSMO_ASSERT(ms->ul_tbf() == NULL); + OSMO_ASSERT(ms->dl_tbf() == dl_tbf[1]); + OSMO_ASSERT(!was_idle); + + ms->detach_tbf(dl_tbf[0]); + OSMO_ASSERT(!ms->is_idle()); + OSMO_ASSERT(ms->ul_tbf() == NULL); + OSMO_ASSERT(ms->dl_tbf() == dl_tbf[1]); + OSMO_ASSERT(!was_idle); + + ms->detach_tbf(dl_tbf[1]); + OSMO_ASSERT(ms->is_idle()); + OSMO_ASSERT(ms->ul_tbf() == NULL); + OSMO_ASSERT(ms->dl_tbf() == NULL); + OSMO_ASSERT(was_idle); + + delete ms; + + talloc_free(dl_tbf[0]); + talloc_free(dl_tbf[1]); + talloc_free(ul_tbf); + + printf("=== end %s ===\n", __func__); +} + + +static const struct log_info_cat default_categories[] = { + {"DPCU", "", "GPRS Packet Control Unit (PCU)", LOGL_INFO, 1}, +}; + +static int filter_fn(const struct log_context *ctx, + struct log_target *tar) +{ + return 1; +} + +const struct log_info debug_log_info = { + filter_fn, + (struct log_info_cat*)default_categories, + ARRAY_SIZE(default_categories), +}; + +int main(int argc, char **argv) +{ + struct vty_app_info pcu_vty_info = {0}; + + tall_pcu_ctx = talloc_named_const(NULL, 1, "MsTest context"); + if (!tall_pcu_ctx) + abort(); + + msgb_set_talloc_ctx(tall_pcu_ctx); + osmo_init_logging(&debug_log_info); + log_set_use_color(osmo_stderr_target, 0); + log_set_print_filename(osmo_stderr_target, 0); + log_set_log_level(osmo_stderr_target, LOGL_INFO); + + vty_init(&pcu_vty_info); + pcu_vty_init(&debug_log_info); + + test_ms_state(); + test_ms_callback(); + test_ms_replace_tbf(); + + if (getenv("TALLOC_REPORT_FULL")) + talloc_report_full(tall_pcu_ctx, stderr); + + return EXIT_SUCCESS; +} + +extern "C" { +void l1if_pdch_req() { abort(); } +void l1if_connect_pdch() { abort(); } +void l1if_close_pdch() { abort(); } +void l1if_open_pdch() { abort(); } +} diff --git a/tests/ms/MsTest.err b/tests/ms/MsTest.err new file mode 100644 index 0000000..d2e20c4 --- /dev/null +++ b/tests/ms/MsTest.err @@ -0,0 +1,20 @@ +Creating MS object, TLLI = 0xffeeddbb +Attaching TBF to MS object, TLLI = 0xffeeddbb, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL) +Attaching TBF to MS object, TLLI = 0xffeeddbb, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL) +Detaching TBF from MS object, TLLI = 0xffeeddbb, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL) +Detaching TBF from MS object, TLLI = 0xffeeddbb, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL) +Destroying MS object, TLLI = 0xffeeddbb +Creating MS object, TLLI = 0xffeeddbb +Attaching TBF to MS object, TLLI = 0xffeeddbb, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL) +Attaching TBF to MS object, TLLI = 0xffeeddbb, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL) +Detaching TBF from MS object, TLLI = 0xffeeddbb, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL) +Detaching TBF from MS object, TLLI = 0xffeeddbb, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL) +Destroying MS object, TLLI = 0xffeeddbb +Creating MS object, TLLI = 0xffeeddbb +Attaching TBF to MS object, TLLI = 0xffeeddbb, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL) +Attaching TBF to MS object, TLLI = 0xffeeddbb, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL) +Detaching TBF from MS object, TLLI = 0xffeeddbb, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL) +Attaching TBF to MS object, TLLI = 0xffeeddbb, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL) +Detaching TBF from MS object, TLLI = 0xffeeddbb, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=NULL) +Detaching TBF from MS object, TLLI = 0xffeeddbb, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL) +Destroying MS object, TLLI = 0xffeeddbb diff --git a/tests/ms/MsTest.ok b/tests/ms/MsTest.ok new file mode 100644 index 0000000..a0d4e9e --- /dev/null +++ b/tests/ms/MsTest.ok @@ -0,0 +1,10 @@ +=== start test_ms_state === +=== end test_ms_state === +=== start test_ms_callback === + ms_active() was called + ms_idle() was called +=== end test_ms_callback === +=== start test_ms_replace_tbf === + ms_active() was called + ms_idle() was called +=== end test_ms_replace_tbf === diff --git a/tests/testsuite.at b/tests/testsuite.at index 2a21a93..f1f4032 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -29,3 +29,10 @@ cat $abs_srcdir/types/TypesTest.ok > expout cat $abs_srcdir/types/TypesTest.err > experr AT_CHECK([$OSMO_QEMU $abs_top_builddir/tests/types/TypesTest], [0], [expout], [experr]) AT_CLEANUP + +AT_SETUP([ms]) +AT_KEYWORDS([ms]) +cat $abs_srcdir/ms/MsTest.ok > expout +cat $abs_srcdir/ms/MsTest.err > experr +AT_CHECK([$OSMO_QEMU $abs_top_builddir/tests/ms/MsTest], [0], [expout], [experr]) +AT_CLEANUP