Make random MSISDN assignment optional

Previously if subscriber was automatically created it got assigned
random MSISDN number. Make it optional (defaulting to previous behavior)
by adding following:

* new optional no-extension argument for subscriber-create-on-demand vty
  command
* db unit tests
* vty test

Note: using the db made with new code might result in subscribers with
empty extension. Such subscribers cannot be deleted using old
code. Make sure not to mix db versions or manually fix it by editing
sqlite with external program.

Fixes: OS#1658
Change-Id: Ibbc2e88e4722b08854ebc631485f19ed56443cbb
diff --git a/openbsc/tests/db/db_test.c b/openbsc/tests/db/db_test.c
index dc81481..755a6e9 100644
--- a/openbsc/tests/db/db_test.c
+++ b/openbsc/tests/db/db_test.c
@@ -28,6 +28,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
+#include <stdbool.h>
 #include <inttypes.h>
 
 static struct gsm_network dummy_net;
@@ -159,12 +160,13 @@
 	subscr_put(rcv_subscr);
 }
 
-static void test_subs(const char *alice_imsi, char *imei1, char *imei2)
+static void test_subs(const char *imsi, char *imei1, char *imei2, bool make_ext)
 {
 	struct gsm_subscriber *alice = NULL, *alice_db;
 	char scratch_str[256];
 
-	alice = db_create_subscriber(alice_imsi, GSM_MIN_EXTEN, GSM_MAX_EXTEN);
+	alice = db_create_subscriber(imsi, GSM_MIN_EXTEN, GSM_MAX_EXTEN,
+				     make_ext);
 	db_subscriber_assoc_imei(alice, imei1);
 	if (imei2)
 		db_subscriber_assoc_imei(alice, imei2);
@@ -177,7 +179,7 @@
 	COMPARE(alice, alice_db);
 	SUBSCR_PUT(alice_db);
 	/* Get by IMSI */
-	alice_db = db_get_subscriber(GSM_SUBSCRIBER_IMSI, alice_imsi);
+	alice_db = db_get_subscriber(GSM_SUBSCRIBER_IMSI, imsi);
 	COMPARE(alice, alice_db);
 	SUBSCR_PUT(alice_db);
 	/* Get by id */
@@ -187,8 +189,14 @@
 	SUBSCR_PUT(alice_db);
 	/* Get by extension */
 	alice_db = db_get_subscriber(GSM_SUBSCRIBER_EXTENSION, alice->extension);
-	COMPARE(alice, alice_db);
-	SUBSCR_PUT(alice_db);
+	if (alice_db) {
+		if (!make_ext)
+			printf("FAIL: bogus extension created for IMSI %s\n",
+			       imsi);
+		COMPARE(alice, alice_db);
+		SUBSCR_PUT(alice_db);
+	} else if (make_ext)
+		printf("FAIL: no subscriber extension for IMSI %s\n", imsi);
 	SUBSCR_PUT(alice);
 }
 
@@ -217,18 +225,22 @@
 	struct gsm_subscriber *alice_db;
 
 	char *alice_imsi = "3243245432345";
-	alice = db_create_subscriber(alice_imsi, GSM_MIN_EXTEN, GSM_MAX_EXTEN);
+	alice = db_create_subscriber(alice_imsi, GSM_MIN_EXTEN, GSM_MAX_EXTEN,
+				     true);
 	db_sync_subscriber(alice);
 	alice_db = db_get_subscriber(GSM_SUBSCRIBER_IMSI, alice->imsi);
 	COMPARE(alice, alice_db);
 	SUBSCR_PUT(alice_db);
 	SUBSCR_PUT(alice);
 
-	test_subs("3693245423445", "1234567890", NULL);
-	test_subs("9993245423445", "1234567890", "6543560920");
+	test_subs("3693245423445", "1234567890", NULL, true);
+	test_subs("9993245423445", "1234567890", "6543560920", true);
+	test_subs("3123122223445", "1234567890", NULL, false);
+	test_subs("9123121223445", "1234567890", "6543560920", false);
 
 	/* create it again and see it fails */
-	alice = db_create_subscriber(alice_imsi, GSM_MIN_EXTEN, GSM_MAX_EXTEN);
+	alice = db_create_subscriber(alice_imsi, GSM_MIN_EXTEN, GSM_MAX_EXTEN,
+				     true);
 	OSMO_ASSERT(!alice);
 
 	test_sms();
diff --git a/openbsc/tests/vty_test_runner.py b/openbsc/tests/vty_test_runner.py
index bae1866..23939e8 100644
--- a/openbsc/tests/vty_test_runner.py
+++ b/openbsc/tests/vty_test_runner.py
@@ -244,7 +244,7 @@
         self.vty.command("configure terminal")
         self.vty.command("nitb")
         self.assertTrue(self.vty.verify("subscriber-create-on-demand", ['']))
-        self.assertTrue(self.vty.verify("subscriber-create-on-demand regexp", ['']))
+        self.assertTrue(self.vty.verify("subscriber-create-on-demand no-extension", ['']))
         self.vty.command("end")
 
     def testSi2Q(self):
@@ -400,6 +400,9 @@
         self.vty.enable()
 
         imsi = "204300854013739"
+        imsi2 = "222301824913762"
+        imsi3 = "333500854113763"
+        imsi4 = "444583744053764"
 
         # Initially we don't have this subscriber
         self.vty.verify('show subscriber imsi '+imsi, ['% No subscriber found for imsi '+imsi])
@@ -407,14 +410,60 @@
         # Lets create one
         res = self.vty.command('subscriber create imsi '+imsi)
         self.assert_(res.find("    IMSI: "+imsi) > 0)
+        self.assert_(res.find("Extension") > 0)
 
         # Now we have it
         res = self.vty.command('show subscriber imsi '+imsi)
         self.assert_(res.find("    IMSI: "+imsi) > 0)
 
+        # With narrow random interval
+        self.vty.command("configure terminal")
+        self.vty.command("nitb")
+        self.assertTrue(self.vty.verify("subscriber-create-on-demand", ['']))
+        # wrong interval
+        res = self.vty.command("subscriber-create-on-demand random 221 122")
+        # error string will contain arguments
+        self.assert_(res.find("122") > 0)
+        self.assert_(res.find("221") > 0)
+        # correct interval - silent ok
+        self.assertTrue(self.vty.verify("subscriber-create-on-demand random 221 222", ['']))
+        self.vty.command("end")
+
+        res = self.vty.command('subscriber create imsi ' + imsi2)
+        self.assert_(res.find("    IMSI: " + imsi2) > 0)
+        self.assert_(res.find("221") > 0 or res.find("222") > 0)
+        self.assert_(res.find("    Extension: ") > 0)
+
+        # Without extension
+        self.vty.command("configure terminal")
+        self.vty.command("nitb")
+        self.assertTrue(self.vty.verify("subscriber-create-on-demand no-extension", ['']))
+        self.vty.command("end")
+        res = self.vty.command('subscriber create imsi ' + imsi3)
+        self.assert_(res.find("    IMSI: " + imsi3) > 0)
+        self.assertEquals(res.find("Extension"), -1)
+
+        # With extension again
+        self.vty.command("configure terminal")
+        self.vty.command("nitb")
+        self.assertTrue(self.vty.verify("no subscriber-create-on-demand", ['']))
+        self.assertTrue(self.vty.verify("subscriber-create-on-demand", ['']))
+        self.assertTrue(self.vty.verify("subscriber-create-on-demand random 221 666", ['']))
+        self.vty.command("end")
+
+        res = self.vty.command('subscriber create imsi ' + imsi4)
+        self.assert_(res.find("    IMSI: " + imsi4) > 0)
+        self.assert_(res.find("    Extension: ") > 0)
+
         # Delete it
         res = self.vty.command('subscriber imsi ' + imsi + ' delete')
         self.assert_("" == res)
+        res = self.vty.command('subscriber imsi ' + imsi2 + ' delete')
+        self.assert_("" == res)
+        res = self.vty.command('subscriber imsi ' + imsi3 + ' delete')
+        self.assert_("" == res)
+        res = self.vty.command('subscriber imsi ' + imsi4 + ' delete')
+        self.assert_("" == res)
 
         # Now it should not be there anymore
         res = self.vty.command('show subscriber imsi '+imsi)