Merge branch 'annotations'

Conflicts:
	oft
diff --git a/oft b/oft
index bfea291..7205505 100755
--- a/oft
+++ b/oft
@@ -157,7 +157,7 @@
     "controller_host"    : "0.0.0.0",  # For passive bind
     "controller_port"    : 6633,
     "relax"              : False,
-    "test_spec"          : "all",
+    "test_spec"          : "",
     "log_file"           : "oft.log",
     "log_append"         : False,
     "list"               : False,
@@ -178,10 +178,6 @@
     "priority"           : 0,
 }
 
-# Default test priority
-TEST_PRIO_DEFAULT=100
-TEST_PRIO_SKIP=-1
-
 #@todo Set up a dict of config params so easier to manage:
 # <param> <cmdline flags> <default value> <help> <optional parser>
 
@@ -211,7 +207,26 @@
     object and args is any additional arguments from the command line
     """
 
-    parser = OptionParser(version="%prog 0.1")
+    usage = "usage: %prog [options] (test|group)..."
+
+    description = """
+OFTest is a framework and set of tests for validating OpenFlow switches.
+
+The default configuration assumes that an OpenFlow 1.0 switch is attempting to
+connect to a controller on the machine running OFTest, port 6633. Additionally,
+the interfaces veth1, veth3, veth5, and veth7 should be connected to the switch's
+dataplane.
+
+If no positional arguments are given then OFTest will run all tests that
+depend only on standard OpenFlow 1.0. Otherwise each positional argument
+is interpreted as either a test name or a test group name. The union of
+these will be executed. To see what groups each test belongs to use the
+--list option.
+"""
+
+    parser = OptionParser(version="%prog 0.1",
+                          usage=usage,
+                          description=description)
 
     #@todo parse port map as option?
     # Set up default values
@@ -233,8 +248,7 @@
                       type="int", help="Port number of the test controller")
     test_list_help = """Indicate tests to run.  Valid entries are "all" (the
         default) or a comma separated list of:
-        module            Run all tests in the named module
-        testcase          Run tests in all modules with the name testcase
+        group             Run all tests in the named group
         module.testcase   Run the specific test case
         """
     parser.add_option("-T", "--test-spec", "--test-list", help=test_list_help)
@@ -244,22 +258,14 @@
                       help="Do not delete log file if specified")
     parser.add_option("--debug",
                       help="Debug lvl: debug, info, warning, error, critical")
-    parser.add_option("--port-count", type="int",
-                      help="Number of ports to use (optional)")
-    parser.add_option("--base-of-port", type="int",
-                      help="Base OpenFlow port number (optional)")
-    parser.add_option("--base-if-index", type="int",
-                      help="Base interface index number (optional)")
     parser.add_option("--list-test-names", action='store_true',
-                      help="List only test names.", default=False)
+                      help="List test names matching the test spec and exit", default=False)
     parser.add_option("--list", action="store_true",
                       help="List all tests and exit")
     parser.add_option("-v", "--verbose", action="store_true",
                       help="Short cut for --debug=verbose")
     parser.add_option("--relax", action="store_true",
                       help="Relax packet match checks allowing other packets")
-    parser.add_option("--param", type="int",
-                      help="Parameter sent to test (for debugging)")
     parser.add_option("--profile", 
                       help="File listing tests to skip/run")
     parser.add_option("-t", "--test-params",
@@ -284,9 +290,6 @@
                       help="Directory containing platform modules")
     parser.add_option("--profile-dir", type="string",
                       help="Directory containing profile modules")
-    parser.add_option("--priority", type="int",
-                      help="Minimum test priority",
-                      default=0)
 
     # Might need this if other parsers want command line
     # parser.allow_interspersed_args = False
@@ -330,6 +333,9 @@
 
     Test cases are subclasses of unittest.TestCase
 
+    Also updates the _groups member to include "standard" and
+    module test groups if appropriate.
+
     @param config The oft configuration dictionary
     @returns A dictionary from test module names to tuples of
     (module, dictionary from test names to test classes).
@@ -355,65 +361,48 @@
             tests = dict((k, v) for (k, v) in mod.__dict__.items() if type(v) == type and
                                                                       issubclass(v, unittest.TestCase))
             if tests:
+                for (testname, test) in tests.items():
+                    # Set default annotation values
+                    if not hasattr(test, "_groups"):
+                        test._groups = []
+                    if not hasattr(test, "_nonstandard"):
+                        test._nonstandard = False
+                    if not hasattr(test, "_disabled"):
+                        test._disabled = False
+
+                    # Put test in its module's test group
+                    if not test._disabled:
+                        test._groups.append(modname)
+
+                    # Put test in the standard test group
+                    if not test._disabled and not test._nonstandard:
+                        test._groups.append("standard")
+                        test._groups.append("all") # backwards compatibility
+
                 result[modname] = (mod, tests)
 
     return result
 
-def prune_tests(test_spec, test_modules):
+def prune_tests(test_specs, test_modules):
     """
-    Return tests matching a given test-spec.
-    @param test_spec A test-spec string.
+    Return tests matching the given test-specs
+    @param test_specs A list of group names or test names.
     @param test_modules Same format as the output of load_test_modules.
     @returns Same format as the output of load_test_modules.
     """
     result = {}
-    for (spec_modname, spec_testname) in parse_test_spec(test_spec):
+    for e in test_specs:
         matched = False
         for (modname, (mod, tests)) in test_modules.items():
-            if (spec_modname == None or spec_modname == modname):
-                for (testname, test) in tests.items():
-                    if (spec_testname == None or spec_testname == testname):
-                            result.setdefault(modname, (mod, {}))
-                            result[modname][1][testname] = test
-                            matched = True
+            for (testname, test) in tests.items():
+                if e in test._groups or e == "%s.%s" % (modname, testname):
+                    result.setdefault(modname, (mod, {}))
+                    result[modname][1][testname] = test
+                    matched = True
         if not matched:
-            if spec_modname and spec_testname:
-                el = "%s.%s" % (spec_modname, spec_testname)
-            else:
-                el = spec_modname or spec_testname or "all"
-            die("test-spec element %s did not match any tests" % el)
+            die("test-spec element %s did not match any tests" % e)
     return result
 
-def parse_test_spec(test_spec):
-    """
-    The input string is split on commas and each element is parsed
-    individually into a module name and test name. Either may be None
-    for a wildcard. The case of the first letter resolves ambiguity
-    of whether a word is a test or module name. The special string
-    "all" results in both fields wildcarded.
-
-    Examples:
-      basic.Echo -> ("basic", "Echo")
-      basic -> ("basic", None)
-      Echo -> (None, "Echo")
-      all -> (None, None)
-    """
-    results = []
-    for ts_entry in test_spec.split(","):
-        parts = ts_entry.split(".")
-        if len(parts) == 1:
-            if ts_entry == "all":
-                results.append((None, None))
-            elif ts_entry[0].isupper():
-                results.append((None, ts_entry))
-            else:
-                results.append((ts_entry, None))
-        elif len(parts) == 2:
-            results.append((parts[0], parts[1]))
-        else:
-            die("Bad test spec: " + ts_entry)
-    return results
-
 def die(msg, exit_val=1):
     print msg
     logging.critical(msg)
@@ -429,23 +418,6 @@
         return " " * spaces
     return " "
 
-def test_prio_get(test):
-    """
-    Return the priority of a test
-
-    If test is in "skip list" from profile, return the skip value
-
-    If the priority property is set in the class, return
-    that value.  Otherwise return 100 (default)
-    """
-    if test.__name__ in profile_mod.skip_test_list:
-        logging.info("Skipping test %s due to profile" % test.__name__)
-        return TEST_PRIO_SKIP
-    if test.__name__ in profile_mod.run_test_list:
-        logging.info("Add test %s due to profile" % test.__name__)
-        return TEST_PRIO_DEFAULT
-    return getattr(test, "priority", TEST_PRIO_DEFAULT)
-
 #
 # Main script
 #
@@ -460,7 +432,14 @@
 # Allow tests to import each other
 sys.path.append(config["test_dir"])
 
-test_modules = prune_tests(config["test_spec"], load_test_modules(config))
+test_specs = args
+if config["test_spec"] != "":
+    print >> sys.stderr, "WARNING: The --test-spec option is deprecated"
+    test_specs += config["test_spec"].split(',')
+if test_specs == []:
+    test_specs = ["standard"]
+
+test_modules = load_test_modules(config)
 
 load_profile(config)
 
@@ -468,18 +447,43 @@
 if config["list"]:
     mod_count = 0
     test_count = 0
-    print "\nTest List:"
+    all_groups = set()
+    print """\
+Tests are shown grouped by module. If a test is in any groups beyond "standard"
+and its module's group then they are shown in parentheses."""
+    print
+    print """\
+Tests marked with '*' are non-standard and may require vendor extensions or
+special switch configuration. These are not part of the "standard" test group."""
+    print
+    print """\
+Tests marked with '!' are disabled because they are experimental, special-purpose,
+or are too long to be run normally. These are not part of the "standard" test
+group or their module's test group."""
+    print
+    print "Tests marked (TP1) after name take --test-params including:"
+    print "    'vid=N;strip_vlan=bool;add_vlan=bool'"
+    print "Note that --profile may override which tests are run"
+    print
+    print "Test List:"
     for (modname, (mod, tests)) in test_modules.items():
         mod_count += 1
         desc = (mod.__doc__ or "No description").strip().split('\n')[0]
         start_str = "  Module " + mod.__name__ + ": "
         print start_str + _space_to(22, start_str) + desc
         for (testname, test) in tests.items():
-            desc = (test.__doc__ or "No description").strip().split('\n')[0]
-            if test_prio_get(test) < config["priority"]:
-                start_str = "  * " + testname + ":"
-            else:
-                start_str = "    " + testname + ":"
+            try:
+                desc = (test.__doc__ or "").strip()
+                desc = desc.split('\n')[0]
+            except:
+                desc = "No description"
+            groups = set(test._groups) - set(["all", "standard", modname])
+            all_groups.update(test._groups)
+            if groups:
+                desc = "(%s) %s" % (",".join(groups), desc)
+            start_str = " %s%s %s:" % (test._nonstandard and "*" or " ",
+                                       test._disabled and "!" or " ",
+                                       testname)
             if len(start_str) > 22:
                 desc = "\n" + _space_to(22, "") + desc
             print start_str + _space_to(22, start_str) + desc
@@ -488,18 +492,17 @@
     print "%d modules shown with a total of %d tests" % \
         (mod_count, test_count)
     print
-    print "Tests preceded by * are not run by default"
-    print "Tests marked (TP1) after name take --test-params including:"
-    print "    'vid=N;strip_vlan=bool;add_vlan=bool'"
-    print "Note that --profile may override which tests are run"
+    print "Test groups: %s" % (', '.join(sorted(all_groups)))
+
     sys.exit(0)
 
+test_modules = prune_tests(test_specs, test_modules)
+
 # Check if test list is requested; display and exit if so
 if config["list_test_names"]:
     for (modname, (mod, tests)) in test_modules.items():
         for (testname, test) in tests.items():
-            if test_prio_get(test) >= config["priority"]:
-                print "%s.%s" % (modname, testname)
+            print "%s.%s" % (modname, testname)
     sys.exit(0)
 
 # Generate the test suite
@@ -508,9 +511,8 @@
 
 for (modname, (mod, tests)) in test_modules.items():
     for (testname, test) in tests.items():
-        if test_prio_get(test) >= config["priority"]:
-            logging.info("Adding test " + modname + "." + testname)
-            suite.addTest(test())
+        logging.info("Adding test " + modname + "." + testname)
+        suite.addTest(test())
 
 # Allow platforms to import each other
 sys.path.append(config["platform_dir"])
diff --git a/src/python/oftest/testutils.py b/src/python/oftest/testutils.py
index 943d41e..e8dec6e 100644
--- a/src/python/oftest/testutils.py
+++ b/src/python/oftest/testutils.py
@@ -1020,3 +1020,31 @@
     finally:
         sys.stdout = backup
     return out
+
+def nonstandard(cls):
+    """
+    Testcase decorator that marks the test as being non-standard.
+    These tests are not automatically added to the "standard" group.
+    """
+    cls._nonstandard = True
+    return cls
+
+def disabled(cls):
+    """
+    Testcase decorator that marks the test as being disabled.
+    These tests are not automatically added to the "standard" group or
+    their module's group.
+    """
+    cls._disabled = True
+    return cls
+
+def group(name):
+    """
+    Testcase decorator that adds the test to a group.
+    """
+    def fn(cls):
+        if not hasattr(cls, "_groups"):
+            cls._groups = []
+        cls._groups.append(name)
+        return cls
+    return fn
diff --git a/tests/basic.py b/tests/basic.py
index 8bb6b00..16f3b31 100644
--- a/tests/basic.py
+++ b/tests/basic.py
@@ -33,6 +33,7 @@
 
 TEST_VID_DEFAULT = 2
 
+@group('smoke')
 class Echo(base_tests.SimpleProtocol):
     """
     Test echo response with no data
@@ -64,6 +65,7 @@
         self.assertEqual(request.data, response.data,
                          'response data does not match request')
 
+@group('smoke')
 class PacketIn(base_tests.SimpleDataPlane):
     """
     Test packet in function
@@ -115,6 +117,7 @@
                                    'Response packet does not match send packet' +
                                    ' for port ' + str(of_port))
 
+@nonstandard
 class PacketInDefaultDrop(base_tests.SimpleDataPlane):
     """
     Test packet in function
@@ -123,8 +126,6 @@
     in message is received from the controller for each
     """
 
-    priority = -1
-
     def runTest(self):
         delete_all_flows(self.controller)
         do_barrier(self.controller)
@@ -149,6 +150,7 @@
                             'Packet in message received on port ' + 
                             str(of_port))
 
+@nonstandard
 class PacketInBroadcastCheck(base_tests.SimpleDataPlane):
     """
     Check if bcast pkts leak when no flows are present
@@ -158,8 +160,6 @@
     Look for the packet on other dataplane ports.
     """
 
-    priority = -1
-
     def runTest(self):
         # Need at least two ports
         self.assertTrue(len(config["port_map"]) > 1, "Too few ports for test")
@@ -178,6 +178,7 @@
         self.assertTrue(pkt_in is None,
                         'BCast packet received on port ' + str(of_port))
 
+@group('smoke')
 class PacketOut(base_tests.SimpleDataPlane):
     """
     Test packet out function
@@ -266,6 +267,7 @@
                                  set(of_ports).difference(dp_ports),
                                  self)
 
+@disabled
 class FlowStatsGet(base_tests.SimpleProtocol):
     """
     Get stats 
@@ -273,8 +275,6 @@
     Simply verify stats get transaction
     """
 
-    priority = -1
-
     def runTest(self):
         logging.info("Running StatsGet")
         logging.info("Inserting trial flow")
@@ -337,6 +337,7 @@
         request = flow_mod_gen(config["port_map"], True)
         self.controller.message_send(request)
 
+@group('smoke')
 class PortConfigMod(base_tests.SimpleProtocol):
     """
     Modify a bit in port config and verify changed
@@ -416,6 +417,7 @@
 
         self.assertTrue(response is not None, 'Did not receive error message')
 
+@group('smoke')
 class BadMessage(base_tests.SimpleProtocol):
     """
     Send a message with a bad type and verify an error is returned
diff --git a/tests/bsn_ipmask.py b/tests/bsn_ipmask.py
index 9f0838f..fea7caa 100644
--- a/tests/bsn_ipmask.py
+++ b/tests/bsn_ipmask.py
@@ -36,13 +36,12 @@
     else:
         return (1 << (63 - index)) - 1
 
+@nonstandard
 class BSNConfigIPMask(base_tests.SimpleDataPlane):
     """
     Exercise BSN vendor extension for configuring IP source/dest match mask
     """
 
-    priority = -1
-
     def bsn_set_ip_mask(self, index, mask):
         """
         Use the BSN_SET_IP_MASK vendor command to change the IP mask for the
diff --git a/tests/bsn_mirror.py b/tests/bsn_mirror.py
index e2d895e..10c3f93 100644
--- a/tests/bsn_mirror.py
+++ b/tests/bsn_mirror.py
@@ -75,14 +75,13 @@
 
 action_list.action_object_map[ofp.OFPAT_VENDOR] = bsn_action_mirror
 
+@nonstandard
 class BSNMirrorAction(base_tests.SimpleDataPlane):
     """
     Exercise BSN vendor extension for copying packets to a mirror destination
     port
     """
 
-    priority = -1
-
     def bsn_set_mirroring(self, enabled):
         """
         Use the BSN_SET_MIRRORING vendor command to enable/disable
diff --git a/tests/caps.py b/tests/caps.py
index 55bedd8..c75bd56 100644
--- a/tests/caps.py
+++ b/tests/caps.py
@@ -90,7 +90,7 @@
     time.sleep(flow_count / 100)
 
 
-
+@disabled
 class FillTableExact(base_tests.SimpleProtocol):
     """
     Fill the flow table with exact matches; can take a while
@@ -109,12 +109,11 @@
     you can control which table to check.
     """
 
-    priority = -1
-
     def runTest(self):
         logging.info("Running " + str(self))
         flow_caps_common(self)
 
+@disabled
 class FillTableWC(base_tests.SimpleProtocol):
     """
     Fill the flow table with wildcard matches
@@ -135,8 +134,6 @@
 
     """
 
-    priority = -1
-
     def runTest(self):
         logging.info("Running " + str(self))
         flow_caps_common(self, is_exact=False)
diff --git a/tests/cxn.py b/tests/cxn.py
index 5718c66..4b3ee59 100644
--- a/tests/cxn.py
+++ b/tests/cxn.py
@@ -19,12 +19,12 @@
 
 from oftest.testutils import *
 
+@disabled
 class BaseHandshake(unittest.TestCase):
     """
     Base handshake case to set up controller, but do not send hello.
     """
 
-    priority = -1
     controllers = []
     default_timeout = 2
 
@@ -100,13 +100,12 @@
         self.assertTrue(self.controllers[0].wait_disconnected(timeout=10),
                         "Not notified of controller disconnect")
 
+@disabled
 class CompleteHandshake(BaseHandshake):
     """
     Set up multiple controllers and complete handshake, but otherwise do nothing.
     """
 
-    priority = -1
-
     def buildControllerList(self):                                             
         # controller_list is a list of IP:port tuples
         con_list = test_param_get('controller_list')
@@ -247,34 +246,31 @@
                break
             time.sleep(tick)
 
+@disabled
 class HandshakeAndKeepalive(CompleteHandshake):
     """
     Complete handshake and respond to echo request, but otherwise do nothing.
     Good for manual testing.
     """
 
-    priority = -1
-
     def __init__(self):
        CompleteHandshake.__init__(self, keep_alive=True)
 
+@disabled
 class HandshakeNoEcho(CompleteHandshake):
     """
     Complete handshake, but otherwise do nothing, and do not respond to echo.
     """
 
-    priority = -1
-
     def __init__(self):
        CompleteHandshake.__init__(self, keep_alive=False)
 
+@disabled
 class HandshakeAndDrop(CompleteHandshake):
     """
     Complete handshake, but otherwise do nothing, and drop connection after a while.
     """
 
-    priority = -1
-
     def __init__(self):
        CompleteHandshake.__init__(self, keep_alive=True, controller_timeout=10)
 
diff --git a/tests/flow_query.py b/tests/flow_query.py
index 5c5954e..476cd75 100644
--- a/tests/flow_query.py
+++ b/tests/flow_query.py
@@ -1666,6 +1666,7 @@
 # Disabled.
 # Should be DUT dependent.
 
+@nonstandard
 class Flow_Add_5_1(base_tests.SimpleProtocol):
     """
     Test FLOW_ADD_5.1 from draft top-half test plan
@@ -1674,8 +1675,6 @@
     None
     """
 
-    priority = -1
-    
     def runTest(self):
         logging.info("Flow_Add_5_1 TEST BEGIN")
 
@@ -1783,6 +1782,7 @@
 # Disabled because of bogus capacity reported by OVS.
 # Should be DUT dependent.
 
+@nonstandard
 class Flow_Add_6(base_tests.SimpleProtocol):
     """
     Test FLOW_ADD_6 from draft top-half test plan
@@ -1791,8 +1791,6 @@
     num_flows - Number of flows to generate
     """
 
-    priority = -1
-
     def runTest(self):
         logging.info("Flow_Add_6 TEST BEGIN")
 
diff --git a/tests/load.py b/tests/load.py
index 9977027..0ad14e9 100644
--- a/tests/load.py
+++ b/tests/load.py
@@ -30,6 +30,7 @@
 
 from oftest.testutils import *
 
+@nonstandard
 class LoadBarrier(base_tests.SimpleProtocol):
     """
     Test barrier under load with loopback
@@ -44,8 +45,6 @@
     the test fails.
     """
 
-    priority = -1
-
     def runTest(self):
         # Set up flow to send from port 1 to port 2 and copy to CPU
         # Test parameter gives LB port base (assumes consecutive)
diff --git a/tests/message_types.py b/tests/message_types.py
index 889c281..7785f36 100644
--- a/tests/message_types.py
+++ b/tests/message_types.py
@@ -111,6 +111,7 @@
                                'Message field code is not OFPBRC_BAD_VERSION')
 
 
+@group('smoke')
 class FeaturesReplyBody(base_tests.SimpleProtocol):
     """Verify the body of Features Reply message"""
 
@@ -491,14 +492,12 @@
         self.assertEqual(response.in_port,of_ports[0],"PacketIn in_port or recieved port field is incorrect")
 
 
-
+@nonstandard
 class PortStatusMessage(base_tests.SimpleDataPlane):
 
     """Verify Port Status Messages are sent to the controller 
     whenever physical ports are added, modified or deleted"""
 
-    priority = -1
-    
     def runTest(self):
         
         logging.info("Running PortStatusMessage Test")
diff --git a/tests/nicira_role.py b/tests/nicira_role.py
index a8ac8cf..fa4cc97 100644
--- a/tests/nicira_role.py
+++ b/tests/nicira_role.py
@@ -19,13 +19,12 @@
 
 NXT_ROLE_VALUE = dict( other=0, slave=1, master=2 )
 
+@nonstandard
 class NiciraRoleRequest(base_tests.SimpleDataPlane):
     """
     Exercise Nicira vendor extension for requesting HA roles
     """
 
-    priority = 0
-
     def nicira_role_request(self, role):
         """
         Use the BSN_SET_IP_MASK vendor command to change the IP mask for the
diff --git a/tests/pktact.py b/tests/pktact.py
index 17b555f..7d30698 100644
--- a/tests/pktact.py
+++ b/tests/pktact.py
@@ -78,6 +78,7 @@
 
 TEST_VID_DEFAULT = 2
 
+@group('smoke')
 class DirectPacket(base_tests.SimpleDataPlane):
     """
     Send packet to single egress port
@@ -146,6 +147,7 @@
             self.assertEqual(str(pkt), str(rcv_pkt),
                              'Response packet does not match send packet')
 
+@group('smoke')
 class DirectPacketController(base_tests.SimpleDataPlane):
     """
     Send packet to the controller port
@@ -927,13 +929,12 @@
         vid = test_param_get('vid', default=TEST_VID_DEFAULT)
         flow_match_test(self, config["port_map"], dl_vlan=vid)
 
+@disabled
 class ExactMatchTaggedMany(BaseMatchCase):
     """
     ExactMatchTagged with many VLANS
     """
 
-    priority = -1
-
     def runTest(self):
         for vid in range(2,100,10):
             flow_match_test(self, config["port_map"], dl_vlan=vid, max_test=5)
@@ -1103,6 +1104,7 @@
         self.verifyFlow(of_ports[0], of_ports[2])
         
 
+@group("smoke")
 class WildcardPriorityWithDelete(SingleWildcardMatchPriority):
     """
     1. Add wildcard match flow, verify packet received.
@@ -1236,7 +1238,7 @@
         flow_match_test(self, config["port_map"], wildcards=ofp.OFPFW_ALL, 
                         dl_vlan=vid)
 
-    
+@group('smoke')
 class AddVLANTag(BaseMatchCase):
     """
     Add a VLAN tag to an untagged packet
@@ -1259,13 +1261,12 @@
         flow_match_test(self, config["port_map"], pkt=pkt, 
                         exp_pkt=exp_pkt, action_list=[vid_act])
 
+@disabled
 class PacketOnly(base_tests.DataPlaneOnly):
     """
     Just send a packet thru the switch
     """
 
-    priority = -1
-
     def runTest(self):
         pkt = simple_tcp_packet()
         of_ports = config["port_map"].keys()
@@ -1275,13 +1276,12 @@
         logging.debug("Data: " + str(pkt).encode('hex'))
         self.dataplane.send(ing_port, str(pkt))
 
+@disabled
 class PacketOnlyTagged(base_tests.DataPlaneOnly):
     """
     Just send a packet thru the switch
     """
 
-    priority = -1
-
     def runTest(self):
         vid = test_param_get('vid', default=TEST_VID_DEFAULT)
         pkt = simple_tcp_packet(dl_vlan_enable=True, dl_vlan=vid)
@@ -1688,6 +1688,7 @@
         flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt, 
                         action_list=acts, max_test=2, egr_count=-1)
 
+@group("smoke")
 class ModifyAll(BaseMatchCase):
     """
     Modify all supported fields and output to a port
@@ -1828,6 +1829,7 @@
     ModifyL2SrcDstMC
     ]
 
+@disabled
 class IterCases(BaseMatchCase):
     """
     Iterate over a bunch of test cases
@@ -1835,8 +1837,6 @@
     The cases come from the list above
     """
 
-    priority = -1
-
     def runTest(self):
         count = test_param_get('iter_count', default=10)
         tests_done = 0
@@ -1872,6 +1872,7 @@
 # and modifies tag 4 to tag 5.  Then verify (in addition) that
 # tag 6 does not get modified.
 
+@disabled
 class MixedVLAN(BaseMatchCase):
     """
     Test mixture of VLAN tag actions
@@ -1895,8 +1896,7 @@
     If only VID 5 distinguishes pkt, this will fail on some platforms
     """   
 
-    priority = -1
-
+@group('smoke')
 class MatchEach(base_tests.SimpleDataPlane):
     """
     Check that each match field is actually matched on.
diff --git a/tests/port_stats.py b/tests/port_stats.py
index 8a762e8..5e0648f 100644
--- a/tests/port_stats.py
+++ b/tests/port_stats.py
@@ -129,6 +129,7 @@
     obj.assertTrue(all_packets_received,
                    "Packet received does not match number sent")
 
+@group('smoke')
 class SingleFlowStats(base_tests.SimpleDataPlane):
     """
     Verify flow stats are properly retrieved.