alloc/test: Add test for successive allocation

This test allocates as many as possible UL/DL TBF pairs, shows their
PDCH usage, and checks how many of them has been created
successfully.

Sponsored-by: On-Waves ehf
diff --git a/tests/alloc/AllocTest.cpp b/tests/alloc/AllocTest.cpp
index ebd57c5..95a6cb6 100644
--- a/tests/alloc/AllocTest.cpp
+++ b/tests/alloc/AllocTest.cpp
@@ -390,6 +390,204 @@
 	test_all_alloc_b();
 }
 
+typedef int (*algo_t)(struct gprs_rlcmac_bts *bts,
+		struct GprsMs *ms,
+		struct gprs_rlcmac_tbf *tbf, uint32_t cust, uint8_t single);
+
+static char get_dir_char(uint8_t mask, uint8_t tx, uint8_t rx)
+{
+	return (mask & tx & rx) ? 'C' :
+		(mask & tx)     ? 'U' :
+		(mask & rx)     ? 'D' :
+				  '.';
+}
+
+enum test_mode {
+	TEST_MODE_UL_ONLY,
+	TEST_MODE_DL_ONLY,
+	TEST_MODE_UL_AND_DL,
+	TEST_MODE_DL_AND_UL,
+	TEST_MODE_DL_AFTER_UL,
+	TEST_MODE_UL_AFTER_DL,
+};
+
+static GprsMs *alloc_tbfs(BTS *the_bts, GprsMs *ms, unsigned ms_class,
+	enum test_mode mode)
+{
+	struct gprs_rlcmac_bts *bts;
+	int tfi;
+	uint8_t trx_no;
+
+	bts = the_bts->bts_data();
+
+	gprs_rlcmac_tbf *tbf = NULL;
+
+	/* Allocate what is needed first */
+	switch (mode) {
+	case TEST_MODE_UL_ONLY:
+	case TEST_MODE_DL_AFTER_UL:
+	case TEST_MODE_UL_AND_DL:
+		tfi = the_bts->tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1);
+		if (tfi < 0)
+			return NULL;
+		tbf = tbf_alloc_ul_tbf(bts, ms, tfi, trx_no, ms_class, 0);
+		if (tbf == NULL)
+			return NULL;
+		break;
+	case TEST_MODE_DL_ONLY:
+	case TEST_MODE_UL_AFTER_DL:
+	case TEST_MODE_DL_AND_UL:
+		tfi = the_bts->tfi_find_free(GPRS_RLCMAC_DL_TBF, &trx_no, -1);
+		tbf = tbf_alloc_dl_tbf(bts, ms, tfi, trx_no, ms_class, 0);
+		if (tbf == NULL)
+			return NULL;
+	}
+
+	OSMO_ASSERT(tbf);
+	OSMO_ASSERT(tbf->ms());
+	OSMO_ASSERT(ms == NULL || ms == tbf->ms());
+	ms = tbf->ms();
+
+	GprsMs::Guard guard(ms);
+
+	/* Optionally delete the TBF */
+	switch (mode) {
+	case TEST_MODE_DL_AFTER_UL:
+	case TEST_MODE_UL_AFTER_DL:
+		tbf_free(tbf);
+		break;
+
+	default:
+		break;
+	}
+
+	/* Continue with what is needed next */
+	switch (mode) {
+	case TEST_MODE_UL_ONLY:
+	case TEST_MODE_DL_ONLY:
+		/* We are done */
+		return ms;
+
+	case TEST_MODE_DL_AFTER_UL:
+	case TEST_MODE_UL_AND_DL:
+		return alloc_tbfs(the_bts, ms, ms_class, TEST_MODE_DL_ONLY);
+
+	case TEST_MODE_UL_AFTER_DL:
+	case TEST_MODE_DL_AND_UL:
+		return alloc_tbfs(the_bts, ms, ms_class, TEST_MODE_UL_ONLY);
+	}
+
+	return  NULL;
+}
+
+static void test_successive_allocation(algo_t algo, unsigned min_class,
+	unsigned max_class, enum test_mode mode,
+	unsigned expect_num, const char *text)
+{
+	BTS the_bts;
+	struct gprs_rlcmac_bts *bts;
+	struct gprs_rlcmac_trx *trx;
+	unsigned counter;
+	unsigned ms_class = min_class;
+
+	printf("Going to test assignment with many TBF, %s\n", text);
+
+	bts = the_bts.bts_data();
+	bts->alloc_algorithm = algo;
+
+	trx = &bts->trx[0];
+	trx->pdch[3].enable();
+	trx->pdch[4].enable();
+	trx->pdch[5].enable();
+	trx->pdch[6].enable();
+	trx->pdch[7].enable();
+
+	for (counter = 0; 1; counter += 1) {
+		gprs_rlcmac_tbf *ul_tbf, *dl_tbf;
+		uint8_t ul_slots = 0;
+		uint8_t dl_slots = 0;
+		unsigned i;
+		int tfi = -1;
+		GprsMs *ms;
+
+		ms = alloc_tbfs(&the_bts, NULL, ms_class, mode);
+		if (!ms)
+			break;
+
+		ul_tbf = ms->ul_tbf();
+		dl_tbf = ms->dl_tbf();
+
+		if (ul_tbf) {
+			ul_slots = 1 << ul_tbf->first_common_ts;
+			tfi = ul_tbf->tfi();
+		} else if (dl_tbf) {
+			ul_slots = 1 << dl_tbf->first_common_ts;
+			tfi = dl_tbf->tfi();
+		}
+
+		for (i = 0; dl_tbf && i < ARRAY_SIZE(dl_tbf->pdch); i += 1)
+			if (dl_tbf->pdch[i])
+				dl_slots |= 1 << i;
+
+		printf(" TBF[%d] class %d reserves %c%c%c%c%c%c%c%c\n",
+			tfi, ms_class,
+			get_dir_char(0x01, ul_slots, dl_slots),
+			get_dir_char(0x02, ul_slots, dl_slots),
+			get_dir_char(0x04, ul_slots, dl_slots),
+			get_dir_char(0x08, ul_slots, dl_slots),
+			get_dir_char(0x10, ul_slots, dl_slots),
+			get_dir_char(0x20, ul_slots, dl_slots),
+			get_dir_char(0x40, ul_slots, dl_slots),
+			get_dir_char(0x80, ul_slots, dl_slots));
+
+		ms_class += 1;
+		if (ms_class > max_class)
+			ms_class = min_class;
+	}
+
+	printf("  Successfully allocated %d UL TBFs\n", counter);
+	OSMO_ASSERT(counter >= expect_num);
+}
+
+static void test_successive_allocation()
+{
+	test_successive_allocation(alloc_algorithm_a, 1, 1, TEST_MODE_UL_AND_DL,
+		7, "algorithm A (UL and DL)");
+	test_successive_allocation(alloc_algorithm_b, 10, 10, TEST_MODE_UL_AND_DL,
+		7, "algorithm B class 10 (UL and DL)");
+	test_successive_allocation(alloc_algorithm_b, 12, 12, TEST_MODE_UL_AND_DL,
+		7, "algorithm B class 12 (UL and DL)");
+	test_successive_allocation(alloc_algorithm_b, 1, 12, TEST_MODE_UL_AND_DL,
+		14, "algorithm B class 1-12 (UL and DL)");
+	test_successive_allocation(alloc_algorithm_b, 1, 29, TEST_MODE_UL_AND_DL,
+		18, "algorithm B class 1-29 (UL and DL)");
+
+	test_successive_allocation(alloc_algorithm_a, 1, 1, TEST_MODE_DL_AND_UL,
+		7, "algorithm A (DL and UL)");
+	test_successive_allocation(alloc_algorithm_b, 10, 10, TEST_MODE_DL_AND_UL,
+		7, "algorithm B class 10 (DL and UL)");
+
+	test_successive_allocation(alloc_algorithm_a, 1, 1, TEST_MODE_DL_AFTER_UL,
+		7, "algorithm A (DL after UL)");
+	test_successive_allocation(alloc_algorithm_b, 10, 10, TEST_MODE_DL_AFTER_UL,
+		7, "algorithm B class 10 (DL after UL)");
+
+	test_successive_allocation(alloc_algorithm_a, 1, 1, TEST_MODE_UL_AFTER_DL,
+		7, "algorithm A (UL after DL)");
+	test_successive_allocation(alloc_algorithm_b, 10, 10, TEST_MODE_UL_AFTER_DL,
+		7, "algorithm B class 10 (UL after DL)");
+
+	test_successive_allocation(alloc_algorithm_a, 1, 1, TEST_MODE_UL_ONLY,
+		7, "algorithm A (UL only)");
+	test_successive_allocation(alloc_algorithm_b, 10, 10, TEST_MODE_UL_ONLY,
+		7, "algorithm B class 10 (UL only)");
+
+	test_successive_allocation(alloc_algorithm_a, 1, 1, TEST_MODE_DL_ONLY,
+		7, "algorithm A (DL ONLY)");
+	test_successive_allocation(alloc_algorithm_b, 10, 10, TEST_MODE_DL_ONLY,
+		7, "algorithm B class 10 (DL ONLY)");
+}
+
 int main(int argc, char **argv)
 {
 	tall_pcu_ctx = talloc_named_const(NULL, 1, "moiji-mobile AllocTest context");
@@ -403,6 +601,7 @@
 
 	test_alloc_a();
 	test_alloc_b();
+	test_successive_allocation();
 	return EXIT_SUCCESS;
 }
 
diff --git a/tests/alloc/AllocTest.err b/tests/alloc/AllocTest.err
index 3f285a4..23eea09 100644
--- a/tests/alloc/AllocTest.err
+++ b/tests/alloc/AllocTest.err
@@ -1,2 +1,17 @@
 No TFI available.
 - Failed allocating TS=2, no USF available
+- Failed allocating TS=3, no USF available
+No suitable uplink slots available
+No suitable uplink slots available
+No suitable uplink slots available
+No suitable uplink slots available
+- Failed allocating TS=3, no USF available
+No suitable uplink slots available
+No TFI available.
+No TFI available.
+- Failed allocating TS=3, no USF available
+No suitable uplink slots available
+- Failed allocating TS=3, no USF available
+No suitable uplink slots available
+No TFI available.
+No TFI available.
diff --git a/tests/alloc/AllocTest.ok b/tests/alloc/AllocTest.ok
index 19ae644..f5df0f8 100644
--- a/tests/alloc/AllocTest.ok
+++ b/tests/alloc/AllocTest.ok
@@ -8615,3 +8615,256 @@
 Mass test: TS0(OOOOOOOO)TS7 MS_Class=27
 Mass test: TS0(OOOOOOOO)TS7 MS_Class=28
 Mass test: TS0(OOOOOOOO)TS7 MS_Class=29
+Going to test assignment with many TBF, algorithm A (UL and DL)
+ TBF[0] class 1 reserves ...C....
+ TBF[1] class 1 reserves ...C....
+ TBF[2] class 1 reserves ...C....
+ TBF[3] class 1 reserves ...C....
+ TBF[4] class 1 reserves ...C....
+ TBF[5] class 1 reserves ...C....
+ TBF[6] class 1 reserves ...C....
+  Successfully allocated 7 UL TBFs
+Going to test assignment with many TBF, algorithm B class 10 (UL and DL)
+ TBF[0] class 10 reserves ...DDCD.
+ TBF[1] class 10 reserves ...DDCD.
+ TBF[2] class 10 reserves ...DDCD.
+ TBF[3] class 10 reserves ...DDCD.
+ TBF[4] class 10 reserves ...DDCD.
+ TBF[5] class 10 reserves ...DDCD.
+ TBF[6] class 10 reserves ...DDCD.
+  Successfully allocated 7 UL TBFs
+Going to test assignment with many TBF, algorithm B class 12 (UL and DL)
+ TBF[0] class 12 reserves ...DDCD.
+ TBF[1] class 12 reserves ...DDCD.
+ TBF[2] class 12 reserves ...DDCD.
+ TBF[3] class 12 reserves ...DDCD.
+ TBF[4] class 12 reserves ...DDCD.
+ TBF[5] class 12 reserves ...DDCD.
+ TBF[6] class 12 reserves ...DDCD.
+  Successfully allocated 7 UL TBFs
+Going to test assignment with many TBF, algorithm B class 1-12 (UL and DL)
+ TBF[0] class 1 reserves ...C....
+ TBF[1] class 2 reserves ...DC...
+ TBF[2] class 3 reserves ...DC...
+ TBF[3] class 4 reserves ...DCD..
+ TBF[4] class 5 reserves ...CD...
+ TBF[5] class 6 reserves ...DCD..
+ TBF[6] class 7 reserves ...DCD..
+ TBF[7] class 8 reserves ...DDCD.
+ TBF[8] class 9 reserves ...DCD..
+ TBF[9] class 10 reserves ...DDCD.
+ TBF[10] class 11 reserves ...DDCD.
+ TBF[11] class 12 reserves ...DDCD.
+ TBF[12] class 1 reserves ...C....
+ TBF[13] class 2 reserves ...DC...
+  Successfully allocated 14 UL TBFs
+Going to test assignment with many TBF, algorithm B class 1-29 (UL and DL)
+ TBF[0] class 1 reserves ...C....
+ TBF[1] class 2 reserves ...DC...
+ TBF[2] class 3 reserves ...DC...
+ TBF[3] class 4 reserves ...DCD..
+ TBF[4] class 5 reserves ...CD...
+ TBF[5] class 6 reserves ...DCD..
+ TBF[6] class 7 reserves ...DCD..
+ TBF[7] class 8 reserves ...DDCD.
+ TBF[8] class 9 reserves ...DCD..
+ TBF[9] class 10 reserves ...DDCD.
+ TBF[10] class 11 reserves ...DDCD.
+ TBF[11] class 12 reserves ...DDCD.
+ TBF[12] class 13 reserves ...CDD..
+ TBF[13] class 14 reserves ...CDDD.
+ TBF[14] class 15 reserves ...CDDDD
+ TBF[15] class 16 reserves ...CDDDD
+ TBF[16] class 17 reserves ...CDDDD
+ TBF[17] class 18 reserves ...DDDCD
+  Successfully allocated 18 UL TBFs
+Going to test assignment with many TBF, algorithm A (DL and UL)
+ TBF[0] class 1 reserves ...C....
+ TBF[1] class 1 reserves ...C....
+ TBF[2] class 1 reserves ...C....
+ TBF[3] class 1 reserves ...C....
+ TBF[4] class 1 reserves ...C....
+ TBF[5] class 1 reserves ...C....
+ TBF[6] class 1 reserves ...C....
+  Successfully allocated 7 UL TBFs
+Going to test assignment with many TBF, algorithm B class 10 (DL and UL)
+ TBF[0] class 10 reserves ...DDCD.
+ TBF[1] class 10 reserves ...DDCD.
+ TBF[2] class 10 reserves ...DDCD.
+ TBF[3] class 10 reserves ...DDCD.
+ TBF[4] class 10 reserves ...DDCD.
+ TBF[5] class 10 reserves ...DDCD.
+ TBF[6] class 10 reserves ...DDCD.
+  Successfully allocated 7 UL TBFs
+Going to test assignment with many TBF, algorithm A (DL after UL)
+ TBF[0] class 1 reserves ...C....
+ TBF[1] class 1 reserves ...C....
+ TBF[2] class 1 reserves ...C....
+ TBF[3] class 1 reserves ...C....
+ TBF[4] class 1 reserves ...C....
+ TBF[5] class 1 reserves ...C....
+ TBF[6] class 1 reserves ...C....
+ TBF[7] class 1 reserves ...C....
+ TBF[8] class 1 reserves ...C....
+ TBF[9] class 1 reserves ...C....
+ TBF[10] class 1 reserves ...C....
+ TBF[11] class 1 reserves ...C....
+ TBF[12] class 1 reserves ...C....
+ TBF[13] class 1 reserves ...C....
+ TBF[14] class 1 reserves ...C....
+ TBF[15] class 1 reserves ...C....
+ TBF[16] class 1 reserves ...C....
+ TBF[17] class 1 reserves ...C....
+ TBF[18] class 1 reserves ...C....
+ TBF[19] class 1 reserves ...C....
+ TBF[20] class 1 reserves ...C....
+ TBF[21] class 1 reserves ...C....
+ TBF[22] class 1 reserves ...C....
+ TBF[23] class 1 reserves ...C....
+ TBF[24] class 1 reserves ...C....
+ TBF[25] class 1 reserves ...C....
+ TBF[26] class 1 reserves ...C....
+ TBF[27] class 1 reserves ...C....
+ TBF[28] class 1 reserves ...C....
+ TBF[29] class 1 reserves ...C....
+ TBF[30] class 1 reserves ...C....
+ TBF[31] class 1 reserves ...C....
+  Successfully allocated 32 UL TBFs
+Going to test assignment with many TBF, algorithm B class 10 (DL after UL)
+ TBF[0] class 10 reserves ...DDCD.
+ TBF[1] class 10 reserves ...DDCD.
+ TBF[2] class 10 reserves ...DDCD.
+ TBF[3] class 10 reserves ...DDCD.
+ TBF[4] class 10 reserves ...DDCD.
+ TBF[5] class 10 reserves ...DDCD.
+ TBF[6] class 10 reserves ...DDCD.
+ TBF[7] class 10 reserves ...DDCD.
+ TBF[8] class 10 reserves ...DDCD.
+ TBF[9] class 10 reserves ...DDCD.
+ TBF[10] class 10 reserves ...DDCD.
+ TBF[11] class 10 reserves ...DDCD.
+ TBF[12] class 10 reserves ...DDCD.
+ TBF[13] class 10 reserves ...DDCD.
+ TBF[14] class 10 reserves ...DDCD.
+ TBF[15] class 10 reserves ...DDCD.
+ TBF[16] class 10 reserves ...DDCD.
+ TBF[17] class 10 reserves ...DDCD.
+ TBF[18] class 10 reserves ...DDCD.
+ TBF[19] class 10 reserves ...DDCD.
+ TBF[20] class 10 reserves ...DDCD.
+ TBF[21] class 10 reserves ...DDCD.
+ TBF[22] class 10 reserves ...DDCD.
+ TBF[23] class 10 reserves ...DDCD.
+ TBF[24] class 10 reserves ...DDCD.
+ TBF[25] class 10 reserves ...DDCD.
+ TBF[26] class 10 reserves ...DDCD.
+ TBF[27] class 10 reserves ...DDCD.
+ TBF[28] class 10 reserves ...DDCD.
+ TBF[29] class 10 reserves ...DDCD.
+ TBF[30] class 10 reserves ...DDCD.
+ TBF[31] class 10 reserves ...DDCD.
+  Successfully allocated 32 UL TBFs
+Going to test assignment with many TBF, algorithm A (UL after DL)
+ TBF[0] class 1 reserves ...U....
+ TBF[1] class 1 reserves ...U....
+ TBF[2] class 1 reserves ...U....
+ TBF[3] class 1 reserves ...U....
+ TBF[4] class 1 reserves ...U....
+ TBF[5] class 1 reserves ...U....
+ TBF[6] class 1 reserves ...U....
+  Successfully allocated 7 UL TBFs
+Going to test assignment with many TBF, algorithm B class 10 (UL after DL)
+ TBF[0] class 10 reserves .....U..
+ TBF[1] class 10 reserves .....U..
+ TBF[2] class 10 reserves .....U..
+ TBF[3] class 10 reserves .....U..
+ TBF[4] class 10 reserves .....U..
+ TBF[5] class 10 reserves .....U..
+ TBF[6] class 10 reserves .....U..
+  Successfully allocated 7 UL TBFs
+Going to test assignment with many TBF, algorithm A (UL only)
+ TBF[0] class 1 reserves ...U....
+ TBF[1] class 1 reserves ...U....
+ TBF[2] class 1 reserves ...U....
+ TBF[3] class 1 reserves ...U....
+ TBF[4] class 1 reserves ...U....
+ TBF[5] class 1 reserves ...U....
+ TBF[6] class 1 reserves ...U....
+  Successfully allocated 7 UL TBFs
+Going to test assignment with many TBF, algorithm B class 10 (UL only)
+ TBF[0] class 10 reserves .....U..
+ TBF[1] class 10 reserves .....U..
+ TBF[2] class 10 reserves .....U..
+ TBF[3] class 10 reserves .....U..
+ TBF[4] class 10 reserves .....U..
+ TBF[5] class 10 reserves .....U..
+ TBF[6] class 10 reserves .....U..
+  Successfully allocated 7 UL TBFs
+Going to test assignment with many TBF, algorithm A (DL ONLY)
+ TBF[0] class 1 reserves ...C....
+ TBF[1] class 1 reserves ...C....
+ TBF[2] class 1 reserves ...C....
+ TBF[3] class 1 reserves ...C....
+ TBF[4] class 1 reserves ...C....
+ TBF[5] class 1 reserves ...C....
+ TBF[6] class 1 reserves ...C....
+ TBF[7] class 1 reserves ...C....
+ TBF[8] class 1 reserves ...C....
+ TBF[9] class 1 reserves ...C....
+ TBF[10] class 1 reserves ...C....
+ TBF[11] class 1 reserves ...C....
+ TBF[12] class 1 reserves ...C....
+ TBF[13] class 1 reserves ...C....
+ TBF[14] class 1 reserves ...C....
+ TBF[15] class 1 reserves ...C....
+ TBF[16] class 1 reserves ...C....
+ TBF[17] class 1 reserves ...C....
+ TBF[18] class 1 reserves ...C....
+ TBF[19] class 1 reserves ...C....
+ TBF[20] class 1 reserves ...C....
+ TBF[21] class 1 reserves ...C....
+ TBF[22] class 1 reserves ...C....
+ TBF[23] class 1 reserves ...C....
+ TBF[24] class 1 reserves ...C....
+ TBF[25] class 1 reserves ...C....
+ TBF[26] class 1 reserves ...C....
+ TBF[27] class 1 reserves ...C....
+ TBF[28] class 1 reserves ...C....
+ TBF[29] class 1 reserves ...C....
+ TBF[30] class 1 reserves ...C....
+ TBF[31] class 1 reserves ...C....
+  Successfully allocated 32 UL TBFs
+Going to test assignment with many TBF, algorithm B class 10 (DL ONLY)
+ TBF[0] class 10 reserves ...DDCD.
+ TBF[1] class 10 reserves ...DDCD.
+ TBF[2] class 10 reserves ...DDCD.
+ TBF[3] class 10 reserves ...DDCD.
+ TBF[4] class 10 reserves ...DDCD.
+ TBF[5] class 10 reserves ...DDCD.
+ TBF[6] class 10 reserves ...DDCD.
+ TBF[7] class 10 reserves ...DDCD.
+ TBF[8] class 10 reserves ...DDCD.
+ TBF[9] class 10 reserves ...DDCD.
+ TBF[10] class 10 reserves ...DDCD.
+ TBF[11] class 10 reserves ...DDCD.
+ TBF[12] class 10 reserves ...DDCD.
+ TBF[13] class 10 reserves ...DDCD.
+ TBF[14] class 10 reserves ...DDCD.
+ TBF[15] class 10 reserves ...DDCD.
+ TBF[16] class 10 reserves ...DDCD.
+ TBF[17] class 10 reserves ...DDCD.
+ TBF[18] class 10 reserves ...DDCD.
+ TBF[19] class 10 reserves ...DDCD.
+ TBF[20] class 10 reserves ...DDCD.
+ TBF[21] class 10 reserves ...DDCD.
+ TBF[22] class 10 reserves ...DDCD.
+ TBF[23] class 10 reserves ...DDCD.
+ TBF[24] class 10 reserves ...DDCD.
+ TBF[25] class 10 reserves ...DDCD.
+ TBF[26] class 10 reserves ...DDCD.
+ TBF[27] class 10 reserves ...DDCD.
+ TBF[28] class 10 reserves ...DDCD.
+ TBF[29] class 10 reserves ...DDCD.
+ TBF[30] class 10 reserves ...DDCD.
+ TBF[31] class 10 reserves ...DDCD.
+  Successfully allocated 32 UL TBFs