Initial release of test auto importer
Update models.py to reflect database changes
Add the following columns to autotests table:
* author
* dependencies
* experimental
* run_verify
* test_time
* test_category
* sync_count
Add run_verify to jobs table
Update scheduler to assert with run_verify

Risk: Medium
Visibility: High, people addings tests will now see more fields via the admin frontend

Signed-off-by: Scott Zawalski <scottz@google.com>



git-svn-id: http://test.kernel.org/svn/autotest/trunk@1837 592f7852-d20e-0410-864c-8624ca9c26a4
diff --git a/frontend/afe/doctests/001_rpc_test.txt b/frontend/afe/doctests/001_rpc_test.txt
index 3815736..d3e5679 100644
--- a/frontend/afe/doctests/001_rpc_test.txt
+++ b/frontend/afe/doctests/001_rpc_test.txt
@@ -91,16 +91,25 @@
 True
 
 # tests...
->>> rpc_interface.add_test(name='sleeptest', test_type='Client',
+>>> rpc_interface.add_test(name='sleeptest', test_type='Client', author='Test',
+...                        description='Sleep Test', test_time=1,
+...                        test_category='Functional',
 ...                        test_class='Kernel', path='sleeptest')
 1L
 >>> rpc_interface.modify_test('sleeptest', path='/my/path')
 >>> data = rpc_interface.get_tests()
 >>> data == [{'id': 1L,
 ...           'name': 'sleeptest',
-...           'description': '',
+...           'author': 'Test',
+...           'description': 'Sleep Test',
+...           'dependencies': '',
+...           'experimental': 1,
+...           'sync_count': 1L,
 ...           'test_type': 'Client',
 ...           'test_class': 'Kernel',
+...           'test_time': 'SHORT',
+...           'run_verify': 1,
+...           'test_category': 'Functional',
 ...           'synch_type': 'Asynchronous',
 ...           'path': '/my/path'}]
 True
@@ -303,10 +312,13 @@
 >>> rpc_interface.add_label(name='my_label', kernel_config='my_kernel_config')
 5L
 >>> test_control_path = os.path.join(test_path, 'test.control')
->>> rpc_interface.add_test(name='sleeptest', test_type='Client',
+>>> rpc_interface.add_test(name='sleeptest', test_type='Client', author='Test',
+...                        test_category='Test',
 ...                        test_class='Kernel', path=test_control_path)
 2L
->>> rpc_interface.add_test(name='my_test', test_type='Client',
+>>> test_control_path = os.path.join(test_path, 'test.control.2')
+>>> rpc_interface.add_test(name='my_test', test_type='Client', author='Test',
+...                        test_category='Test',
 ...                        test_class='Kernel', path=test_control_path)
 3L
 >>> rpc_interface.add_host(hostname='my_label_host1')
@@ -387,7 +399,8 @@
 ...         'synch_count': None,
 ...         'synch_type': 'Asynchronous',
 ...         'synchronizing': 0,
-...         'timeout': 72}
+...         'timeout': 72,
+...         'run_verify': 1}
 True
 
 # get_host_queue_entries returns a lot of data, so let's only check a couple
diff --git a/frontend/afe/doctests/test.control.2 b/frontend/afe/doctests/test.control.2
new file mode 100644
index 0000000..653fafe
--- /dev/null
+++ b/frontend/afe/doctests/test.control.2
@@ -0,0 +1 @@
+job.run_test('testname')
diff --git a/frontend/afe/models.py b/frontend/afe/models.py
index 1e48f6d..e9bc2c8 100644
--- a/frontend/afe/models.py
+++ b/frontend/afe/models.py
@@ -189,30 +189,45 @@
 class Test(dbmodels.Model, model_logic.ModelExtensions):
     """\
     Required:
+    author: author name
+    description: description of the test
     name: test name
+    time: short, medium, long
+    test_class: This describes the class for your the test belongs in.
+    test_category: This describes the category for your tests
     test_type: Client or Server
     path: path to pass to run_test()
     synch_type: whether the test should run synchronously or asynchronously
-
+    sync_count:  is a number >=1 (1 being the default). If it's 1, then it's an
+                 async job. If it's >1 it's sync job for that number of machines
+                 i.e. if sync_count = 2 it is a sync job that requires two 
+                 machines. 
     Optional:
-    test_class: used for categorization of tests
-    description: arbirary text description
+    dependencies: What the test requires to run. Comma deliminated list
+    experimental: If this is set to True production servers will ignore the test
+    run_verify: Whether or not the scheduler should run the verify stage
     """
-    Classes = enum.Enum('Kernel', 'Hardware', 'Canned Test Sets',
-                        string_values=True)
+    TestTime = enum.Enum('SHORT', 'MEDIUM', 'LONG', start_value=1)
     SynchType = enum.Enum('Asynchronous', 'Synchronous', start_value=1)
     # TODO(showard) - this should be merged with Job.ControlType (but right
     # now they use opposite values)
     Types = enum.Enum('Client', 'Server', start_value=1)
 
     name = dbmodels.CharField(maxlength=255, unique=True)
-    test_class = dbmodels.CharField(maxlength=255,
-                                    choices=Classes.choices())
+    author = dbmodels.CharField(maxlength=255)
+    test_class = dbmodels.CharField(maxlength=255)
+    test_category = dbmodels.CharField(maxlength=255)
+    dependencies = dbmodels.CharField(maxlength=255, blank=True)
     description = dbmodels.TextField(blank=True)
+    experimental = dbmodels.BooleanField(default=True)
+    run_verify = dbmodels.BooleanField(default=True)
+    test_time = dbmodels.SmallIntegerField(choices=TestTime.choices(),
+                                           default=TestTime.MEDIUM)
     test_type = dbmodels.SmallIntegerField(choices=Types.choices())
+    sync_count = dbmodels.IntegerField(default=1)
     synch_type = dbmodels.SmallIntegerField(choices=SynchType.choices(),
                                             default=SynchType.ASYNCHRONOUS)
-    path = dbmodels.CharField(maxlength=255)
+    path = dbmodels.CharField(maxlength=255, unique=True)
 
     name_field = 'name'
     objects = model_logic.ExtendedManager()
@@ -224,11 +239,12 @@
     class Admin:
         fields = (
             (None, {'fields' :
-                    ('name', 'test_class', 'test_type', 'synch_type',
-                     'path', 'description')}),
+                    ('name', 'author', 'test_category', 'test_class',
+                     'test_time', 'synch_type', 'test_type', 'sync_count',
+                     'path', 'dependencies', 'experimental', 'run_verify',
+                     'description')}),
             )
-        list_display = ('name', 'test_type', 'synch_type',
-                        'description')
+        list_display = ('name', 'test_type', 'description', 'synch_type')
         search_fields = ('name',)
 
     def __str__(self):
@@ -447,6 +463,7 @@
     synch_type: Asynchronous or Synchronous (i.e. job must run on all hosts
                 simultaneously; used for server-side control files)
     synch_count: ???
+    run_verify: Whether or not to run the verify phase
     synchronizing: for scheduler use
     timeout: hours until job times out
     """
@@ -469,6 +486,7 @@
         blank=True, null=True, choices=Test.SynchType.choices())
     synch_count = dbmodels.IntegerField(blank=True, null=True)
     synchronizing = dbmodels.BooleanField(default=False)
+    run_verify = dbmodels.BooleanField(default=True)
     timeout = dbmodels.IntegerField()
 
 
@@ -482,7 +500,7 @@
 
     @classmethod
     def create(cls, owner, name, priority, control_file, control_type,
-               hosts, synch_type, timeout):
+               hosts, synch_type, timeout, run_verify):
         """\
         Creates a job by taking some information (the listed args)
         and filling in the rest of the necessary information.
@@ -491,7 +509,8 @@
         job = cls.add_object(
             owner=owner, name=name, priority=priority,
             control_file=control_file, control_type=control_type,
-            synch_type=synch_type, timeout=timeout)
+            synch_type=synch_type, timeout=timeout,
+            run_verify=run_verify)
 
         if job.synch_type == Test.SynchType.SYNCHRONOUS:
             job.synch_count = len(hosts)
@@ -520,7 +539,8 @@
             owner=new_owner, name=self.name, priority=self.priority,
             control_file=self.control_file,
             control_type=self.control_type, hosts=hosts,
-            synch_type=self.synch_type, timeout=self.timeout)
+            synch_type=self.synch_type, timeout=self.timeout,
+            run_verify=self.run_verify)
         new_job.queue(hosts)
         return new_job
 
diff --git a/frontend/afe/rpc_interface.py b/frontend/afe/rpc_interface.py
index bac3aa8..dba79f4 100644
--- a/frontend/afe/rpc_interface.py
+++ b/frontend/afe/rpc_interface.py
@@ -115,8 +115,16 @@
 
 # tests
 
-def add_test(name, test_type, path, test_class=None, description=None):
+def add_test(name, test_type, path, author=None, dependencies=None,
+             experimental=True, run_verify=None, test_class=None, 
+             test_time=None, test_category=None, description=None,
+             sync_count=1):
     return models.Test.add_object(name=name, test_type=test_type, path=path,
+                                  author=author, dependencies=dependencies,
+                                  experimental=experimental,
+                                  run_verify=run_verify, test_time=test_time,
+                                  test_category=test_category,
+                                  sync_count=sync_count,
                                   test_class=test_class,
                                   description=description).id
 
@@ -253,7 +261,7 @@
 
 def create_job(name, priority, control_file, control_type, timeout=None,
                is_synchronous=None, hosts=None, meta_hosts=None,
-               one_time_hosts=None):
+               run_verify=True, one_time_hosts=None):
     """\
     Create and enqueue a job.
 
@@ -324,7 +332,8 @@
                             control_type=control_type,
                             synch_type=synch_type,
                             hosts=host_objects,
-                            timeout=timeout)
+                            timeout=timeout,
+                            run_verify=run_verify)
     job.queue(host_objects)
     return job.id
 
diff --git a/frontend/migrations/013_new_test_fields.py b/frontend/migrations/013_new_test_fields.py
new file mode 100644
index 0000000..02ce6e8
--- /dev/null
+++ b/frontend/migrations/013_new_test_fields.py
@@ -0,0 +1,20 @@
+def migrate_up(manager):
+    manager.execute('ALTER TABLE jobs ADD run_verify tinyint(1) default 1')
+    manager.execute('ALTER TABLE autotests ADD author VARCHAR(256)')
+    manager.execute('ALTER TABLE autotests ADD dependencies VARCHAR(256)')
+    manager.execute('ALTER TABLE autotests ADD experimental SMALLINT DEFAULT 0')
+    manager.execute('ALTER TABLE autotests ADD run_verify SMALLINT DEFAULT 1')
+    manager.execute('ALTER TABLE autotests ADD test_time SMALLINT DEFAULT 1')
+    manager.execute('ALTER TABLE autotests ADD test_category VARCHAR(256)')
+    manager.execute('ALTER TABLE autotests ADD sync_count INT(11) DEFAULT 1')
+
+
+def migrate_down(manager):
+    manager.execute('ALTER TABLE jobs DROP run_verify')
+    manager.execute('ALTER TABLE autotests DROP sync_count')
+    manager.execute('ALTER TABLE autotests DROP author')
+    manager.execute('ALTER TABLE autotests DROP dependencies')
+    manager.execute('ALTER TABLE autotests DROP experimental')
+    manager.execute('ALTER TABLE autotests DROP run_verify')
+    manager.execute('ALTER TABLE autotests DROP test_time')
+    manager.execute('ALTER TABLE autotests DROP test_category')