7050547 ai_sd/aimdns unit tests failing on machine not configured as AI server
authorMatt Keenan <matt.keenan@oracle.com>
Wed, 31 Aug 2011 10:57:23 +0100
changeset 1435 ffa7838e81ca
parent 1434 b566605accae
child 1436 5cf488252cbc
7050547 ai_sd/aimdns unit tests failing on machine not configured as AI server
usr/src/cmd/auto-install/test/manual/test_ai_sd.py
usr/src/cmd/auto-install/test/test_ai_sd.py
usr/src/cmd/installadm/test/manual/test_aimdns_manual.py
usr/src/cmd/installadm/test/test_aimdns.py
usr/src/tools/tests/README
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/auto-install/test/manual/test_ai_sd.py	Wed Aug 31 10:57:23 2011 +0100
@@ -0,0 +1,135 @@
+#!/usr/bin/python2.6
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+#
+# test_ai_sd - test for AI Service Discovery Engine
+#
+# These tests are deemed better run as manual tests as they require
+# the machine to be configured as an AI server, and as per TTL DNS
+# defaults require 120 second timeouts which is too long for an automatic
+# test to wait around.
+#
+""" test AI Service Discovery Engine
+"""
+
+import gettext
+import subprocess
+import time
+import unittest
+
+from nose.plugins.skip import SkipTest
+
+from solaris_install import Popen
+from solaris_install.auto_install import ai_sd
+
+
+class TestAISD(unittest.TestCase):
+    '''tests for ai_sd'''
+
+    class BogusService(object):
+        '''Class to start and teardown a bogus service.
+        '''
+        dns_sd = "/bin/dns-sd"
+
+        def __init__(self, name, svc_type, domain, port, text):
+            '''
+            Start a dns-sd process advertising a service with name, type with
+            svc_type in the domain provided
+            '''
+            self.proc = subprocess.Popen([self.dns_sd, "-R", name,
+                                          svc_type, domain, port,
+                                          text],
+                                         stdout=subprocess.PIPE,
+                                         stderr=subprocess.STDOUT)
+
+        def __del__(self):
+            '''
+            Kill process on object deletion -- remember to hold object in a
+            variable or this will get called right after creation
+            '''
+            self.proc.terminate()
+            # wait for dns-sd to die
+            time.sleep(0.5)
+
+    TIMEOUT = 2
+    SERVICE_NAME = 'bogus_service'
+    DEFAULT_SERVICE = '_default'
+    REGTYPE = '_OSInstall._tcp'
+    DOMAIN = 'local'
+    PORT = "5555"
+    TEXT_REC = 'aiwebserver=' + SERVICE_NAME + ':' + PORT
+
+    def setUp(self):
+        # Before running any tests, ensure Multicast DNS SMF is enabled.
+        cmd = ["/usr/bin/svcs", "-H", "-o", "STATE",
+               "svc:/network/dns/multicast:default"]
+        p = Popen.check_call(cmd, stdout=Popen.STORE, stderr=Popen.STORE)
+        if p.stdout.strip() != "online":
+            raise SkipTest("Unable to run FindAPI tests - enable SMF service "
+                           "svc:/network/dns/multicast:default")
+        self.bogosvc = None
+
+    def tearDown(self):
+        if self.bogosvc:
+            del(self.bogosvc)
+
+    def test_no_aiservice(self):
+        '''test covers when there is not an AIService'''
+        # Default TTL (Time-To-Live) for DNS records is 120 seconds
+        # To change the 120 second TTL, would require a re-architecture of the
+        # aimdns' records. Instead of doing a default DNSServceRegister we
+        # would need to create a DNS connection, create a record and then
+        # register it with a shorter TTL value. The default value which can not
+        # be modified is 120 seconds.
+        time.sleep(120)
+        aisvc = ai_sd.AIService(self.SERVICE_NAME, self.TIMEOUT)
+        assert aisvc.lookup() == -1, 'lookup succeeded'
+        assert aisvc.found == False, 'found bogus service'
+
+    def test_aiservice(self):
+        '''test covers when there is an AIService'''
+        self.bogosvc = self.BogusService(self.SERVICE_NAME,
+                                    self.REGTYPE,
+                                    self.DOMAIN,
+                                    self.PORT,
+                                    self.TEXT_REC)
+
+        # uncomment out the following lines to see if the service
+        # is actually running.
+        # dns_sd = "/bin/dns-sd"
+        # proc = subprocess.Popen([dns_sd, "-B", self.REGTYPE, self.DOMAIN],
+        #                            stdout=None,
+        #                            stderr=subprocess.STDOUT)
+        # time.sleep(2)
+        # proc.terminate()
+
+        aisvc = ai_sd.AIService(self.SERVICE_NAME, self.TIMEOUT)
+        assert aisvc.lookup() == 0, \
+                'lookup did not succeed for service (%s)' % self.SERVICE_NAME
+        assert aisvc.lookup() != -1, \
+                'lookup did not succeed for service (%s)' % self.SERVICE_NAME
+        assert aisvc.found == True, \
+                'did not find service (%s)' % self.SERVICE_NAME
+
+if __name__ == '__main__':
+    gettext.install("ai", "/usr/lib/locale")
+    unittest.main()
--- a/usr/src/cmd/auto-install/test/test_ai_sd.py	Wed Aug 31 10:25:52 2011 +1000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,122 +0,0 @@
-#!/usr/bin/python2.6
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
-#
-# test_ai_sd - test for AI Service Discovery Engine
-#
-""" test AI Service Discovery Engine
-"""
-
-import gettext
-import subprocess
-import time
-import unittest
-
-from solaris_install.auto_install import ai_sd
-
-
-class TestAISD(unittest.TestCase):
-    '''tests for ai_sd'''
-
-    class BogusService(object):
-        '''Class to start and teardown a bogus service.
-        '''
-        dns_sd = "/bin/dns-sd"
-
-        def __init__(self, name, svc_type, domain, port, text):
-            '''
-            Start a dns-sd process advertising a service with name, type with
-            svc_type in the domain provided
-            '''
-            self.proc = subprocess.Popen([self.dns_sd, "-R", name,
-                                          svc_type, domain, port,
-                                          text],
-                                         stdout=subprocess.PIPE,
-                                         stderr=subprocess.STDOUT)
-
-        def __del__(self):
-            '''
-            Kill process on object deletion -- remember to hold object in a
-            variable or this will get called right after creation
-            '''
-            self.proc.terminate()
-            # wait for dns-sd to die
-            time.sleep(0.5)
-
-    TIMEOUT = 2
-    SERVICE_NAME = 'bogus_service'
-    DEFAULT_SERVICE = '_default'
-    REGTYPE = '_OSInstall._tcp'
-    DOMAIN = 'local'
-    PORT = "5555"
-    TEXT_REC = 'aiwebserver=' + SERVICE_NAME + ':' + PORT
-
-    def setUp(self):
-        self.bogosvc = None
-
-    def tearDown(self):
-        if self.bogosvc:
-            del(self.bogosvc)
-
-    def test_no_aiservice(self):
-        '''test covers when there is not an AIService'''
-        aisvc = ai_sd.AIService(self.SERVICE_NAME, self.TIMEOUT)
-        assert aisvc.lookup() == -1, 'lookup succeeded'
-        assert aisvc.found == False, 'found bogus service'
-
-    def test_aiservice(self):
-        '''test covers when there is an AIService'''
-        self.bogosvc = self.BogusService(self.SERVICE_NAME,
-                                    self.REGTYPE,
-                                    self.DOMAIN,
-                                    self.PORT,
-                                    self.TEXT_REC)
-
-        # uncomment out the following lines to see if the service
-        # is actually running.
-        # dns_sd = "/bin/dns-sd"
-        # proc = subprocess.Popen([dns_sd, "-B", self.REGTYPE, self.DOMAIN],
-        #                            stdout=None,
-        #                            stderr=subprocess.STDOUT)
-        # time.sleep(2)
-        # proc.terminate()
-
-        aisvc = ai_sd.AIService(self.SERVICE_NAME, self.TIMEOUT)
-        assert aisvc.lookup() == 0, \
-                'lookup did not succeed for service (%s)' % self.SERVICE_NAME
-        assert aisvc.lookup() != -1, \
-                'lookup did not succeed for service (%s)' % self.SERVICE_NAME
-        assert aisvc.found == True, \
-                'did not find service (%s)' % self.SERVICE_NAME
-
-        aisvc = ai_sd.AIService(self.DEFAULT_SERVICE, self.TIMEOUT)
-        assert aisvc.lookup() == 0, \
-                'lookup did not succeed for default service'
-        assert aisvc.found == True, \
-                'did not find default service'
-        assert aisvc.get_txt_rec() == self.TEXT_REC, \
-                "found service's text record does not match"
-
-
-if __name__ == '__main__':
-    gettext.install("ai", "/usr/lib/locale")
-    unittest.main()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/installadm/test/manual/test_aimdns_manual.py	Wed Aug 31 10:57:23 2011 +0100
@@ -0,0 +1,253 @@
+#!/usr/bin/python
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+#
+'''Manual Testcase for aimdns
+
+These tests are deemed manual due to the 120 second TTL DNS timeout.
+This is deemed too excessive for automatic tests.
+
+To run these tests, see the instructions in usr/src/tools/tests/README.
+Remember that since the proto area is used for the PYTHONPATH, the gate
+must be rebuilt for these tests to pick up any changes in the tested code.
+'''
+import gettext
+import subprocess
+import time
+import threading
+import unittest
+
+import osol_install.auto_install.aimdns_mod as aimdns
+import osol_install.auto_install.installadm_common as common
+
+from nose.plugins.skip import SkipTest
+
+from solaris_install import CalledProcessError, Popen
+
+
+class RegisterAPI(unittest.TestCase):
+    '''Class: RegisterAPI - used to test the AImDNS class
+    '''
+    bogussvc = "self-registration-test-svc"
+
+    class Register(threading.Thread):
+        '''Class to register a mDNS record in a thread
+        '''
+
+        def __init__(self, mdns_obj, servicename, port, comments):
+            '''
+            Call register on the provided mdns_obj
+            '''
+            threading.Thread.__init__(self)
+            self.mdns = mdns_obj
+            self.servicename = servicename
+            self.port = port
+            self.comments = comments
+
+        def run(self):
+            '''Method to actually register the mDNS record
+            '''
+            self.mdns.register(servicename=self.servicename,
+                               port=self.port, comments=self.comments)
+
+        def __del__(self):
+            '''Method to clear all registrations
+            '''
+            # del(mdns) does not work for the test as it is not called
+            # immediately thus the service is still registered
+            self.mdns.__del__()
+
+    def test_register(self):
+        '''Test the AImDNS().register() method
+        '''
+        mdns = aimdns.AImDNS()
+        mdns.timeout = 2
+        reg = self.Register(mdns, self.bogussvc,
+                            port=9999, comments="bar=foo")
+        reg.start()
+        time.sleep(2)
+
+        # manual output to stdout for debugging
+        # dns_sd = "/bin/dns-sd"
+        # proc = subprocess.Popen([dns_sd, "-B", common.REGTYPE, mdns.domain],
+        #                            stdout=None,
+        #                            stderr=subprocess.STDOUT)
+        # time.sleep(2)
+        # proc.terminate()
+
+        # ensure service exists
+        mdns2 = aimdns.AImDNS()
+        mdns2.timeout = 2
+        assert mdns2.find(servicename=self.bogussvc) == True, \
+               "Did not find unique service: %s!" % self.bogussvc
+
+        # ensure service goes away with module
+        # del(reg) does not work for the test as it is not called
+        # immediately thus the service is still registered causing
+        # the mdns2.find() to fail
+        reg.__del__()
+        time.sleep(0.5)
+
+        mdns2.reset()
+        # negative test -- ensure service nolonger exists
+        # Default TTL (Time-To-Live) for DNS records is 120 seconds
+        # To change the 120 second TTL, would require a re-architecture of the
+        # aimdns' records. Instead of doing a default DNSServceRegister we
+        # would need to create a DNS connection, create a record and then
+        # register it with a shorter TTL value. The default value which can not
+        # be modified is 120 seconds.
+        time.sleep(120)
+        assert mdns2.find(servicename=self.bogussvc) == False, \
+               "Still finding unique service: %s!" % self.bogussvc
+
+
+class FindAPI(unittest.TestCase):
+    '''Class: FindAPI - class to test the find method of the AImDNS class
+    '''
+    bogussvc = "not_likely_to_exist_service"
+
+    class BogusService(object):
+        '''Class to start and teardown a bogus service.
+        '''
+        dns_sd = "/bin/dns-sd"
+
+        def __init__(self, name, svc_type, domain):
+            '''
+            Start a dns-sd process advertising a service with name, type with
+            svc_type in the domain provided
+            '''
+            self.proc = subprocess.Popen([self.dns_sd, "-R", name,
+                                          svc_type, domain, "9999",
+                                          "foo=bar"],
+                                         stdout=subprocess.PIPE,
+                                         stderr=subprocess.STDOUT)
+
+        def __del__(self):
+            '''
+            Kill process on object deletion -- remember to hold object in a
+            variable or this will get called right after creation
+            '''
+            self.proc.terminate()
+            # wait for dns-sd to die
+            time.sleep(0.5)
+
+    def test_find(self):
+        '''Test AImDNS().find() returns True when service is found and False
+           when not found
+        '''
+        mdns = aimdns.AImDNS()
+        mdns.timeout = 2
+        # negative test
+        assert mdns.find(servicename=self.bogussvc) == False, \
+               "Found bogus service: %s!" % self.bogussvc
+
+        # start-up service for a positive test
+        # pylint: disable-msg=W0212
+        bogosvc = self.BogusService(self.bogussvc, common.REGTYPE, mdns.domain)
+        # pylint: enable-msg=W0212
+        assert mdns.find(self.bogussvc) == True, \
+               "Failed to find unique service: %s!" % self.bogussvc
+        del(bogosvc)
+
+    def test_browse(self):
+        '''Test that AImDNS().browse returns True upon finding a service
+        '''
+        mdns = aimdns.AImDNS()
+        mdns.timeout = 2
+        # start up a service to test browse
+        # pylint: disable-msg=W0212
+        bogosvc = self.BogusService(self.bogussvc, common.REGTYPE, mdns.domain)
+        # pylint: enable-msg=W0212
+        assert mdns.browse() == True, "Did not find any services!"
+        del(bogosvc)
+        # Default TTL (Time-To-Live) for DNS records is 120 seconds
+        # To change the 120 second TTL, would require a re-architecture of the
+        # aimdns' records. Instead of doing a default DNSServceRegister we
+        # would need to create a DNS connection, create a record and then
+        # register it with a shorter TTL value. The default value which can not
+        # be modified is 120 seconds.
+        time.sleep(120)
+
+    def test_interfaces(self):
+        '''Verify a unique service shows up for all interfaces listed
+        (since dns-sd publishes on all iterfaces) when doing an
+        AImDNS().browse()
+        '''
+        def _in_network(inter_ipv4, networks):
+            '''Ensures that the interface's address is in networks
+            '''
+            # iterate over the network list
+            for network in networks:
+                # check if the interface's IPv4 address is in the network
+                if common.compare_ipv4(inter_ipv4, network):
+                    return True
+            return False
+
+        # services dictionary looks like:
+        #{'e1000g0': [
+        #    {'domain': u'local', 'hosttarget': u'jumprope.local.',
+        #     'comments': 'aiwebserver=10.10.44.5:46501',
+        #     'servicename': u'install_test_ai_x86',
+        #     'flags': True, 'port': 46501},
+        #    {'domain': u'local', 'hosttarget': u'jumprope.local.',
+        #     'comments': 'foo=bar', 'flags': True, 'port': 9999,
+        #     'servicename': u'not_likely_to_exist_service'}
+        #]}
+
+        mdns = aimdns.AImDNS()
+        mdns.timeout = 2
+
+        # start up a service to test browse
+        # pylint: disable-msg=W0212
+        bogosvc = self.BogusService(self.bogussvc, common.REGTYPE, mdns.domain)
+        # pylint: enable-msg=W0212
+
+        assert mdns.browse() == True, "Did not find any services!"
+        for interface in mdns.services:
+            in_net = _in_network(mdns.interfaces[interface], mdns.networks)
+            if (in_net and not mdns.exclude) or (not in_net and mdns.exclude):
+                assert any([svc for svc in mdns.services[interface] if
+                        svc['servicename'] == self.bogussvc]), \
+                        "Unable to find unique service on interface: %s" % \
+                        interface
+        del(bogosvc)
+
+
+def check_install_SMF():
+    ''' Check if install/server SMF services is available.
+        returning True if available and False if not.
+    '''
+    # Ensure system/install/server SMF service is available
+    cmd = ["/usr/bin/svcs", "svc:/system/install/server"]
+    try:
+        Popen.check_call(cmd, stdout=Popen.DEVNULL, stderr=Popen.DEVNULL)
+    except CalledProcessError:
+        # This system does not have the service so skip the test
+        raise SkipTest("svc:/system/install/server not installed")
+
+
+# Ensure system/install/server SMF service is available
+check_install_SMF()
+
+if __name__ == '__main__':
+    gettext.install("ai", "/usr/lib/locale")
+    unittest.main()
--- a/usr/src/cmd/installadm/test/test_aimdns.py	Wed Aug 31 10:25:52 2011 +1000
+++ b/usr/src/cmd/installadm/test/test_aimdns.py	Wed Aug 31 10:57:23 2011 +0100
@@ -28,10 +28,7 @@
 must be rebuilt for these tests to pick up any changes in the tested code.
 '''
 import gettext
-import subprocess
 import sys
-import time
-import threading
 import unittest
 
 import pybonjour as pyb
@@ -39,179 +36,9 @@
 import osol_install.auto_install.aimdns_mod as aimdns
 import osol_install.auto_install.installadm_common as common
 
-
-class RegisterAPI(unittest.TestCase):
-    '''Class: RegisterAPI - used to test the AImDNS class
-    '''
-    bogussvc = "self-registration-test-svc"
-
-    class Register(threading.Thread):
-        '''Class to register a mDNS record in a thread
-        '''
-
-        def __init__(self, mdns_obj, servicename, port, comments):
-            '''
-            Call register on the provided mdns_obj
-            '''
-            threading.Thread.__init__(self)
-            self.mdns = mdns_obj
-            self.servicename = servicename
-            self.port = port
-            self.comments = comments
-
-        def run(self):
-            '''Method to actually register the mDNS record
-            '''
-            self.mdns.register(servicename=self.servicename,
-                               port=self.port, comments=self.comments)
-
-        def __del__(self):
-            '''Method to clear all registrations
-            '''
-            # del(mdns) does not work for the test as it is not called
-            # immediately thus the service is still registered
-            self.mdns.__del__()
-
-    def test_register(self):
-        '''Test the AImDNS().register() method
-        '''
-        mdns = aimdns.AImDNS()
-        mdns.timeout = 2
-        reg = self.Register(mdns, self.bogussvc,
-                            port=9999, comments="bar=foo")
-        reg.start()
-        time.sleep(2)
-
-        # manual output to stdout for debugging
-        # dns_sd = "/bin/dns-sd"
-        # proc = subprocess.Popen([dns_sd, "-B", common.REGTYPE, mdns.domain],
-        #                            stdout=None,
-        #                            stderr=subprocess.STDOUT)
-        # time.sleep(2)
-        # proc.terminate()
-
-        # ensure service exists
-        mdns2 = aimdns.AImDNS()
-        mdns2.timeout = 2
-        assert mdns2.find(servicename=self.bogussvc) == True, \
-               "Did not find unique service: %s!" % self.bogussvc
-
-        # ensure service goes away with module
-        # del(reg) does not work for the test as it is not called
-        # immediately thus the service is still registered causing
-        # the mdns2.find() to fail
-        reg.__del__()
-        time.sleep(0.5)
-
-        mdns2.reset()
-        # negative test -- ensure service nolonger exists
-        assert mdns2.find(servicename=self.bogussvc) == False, \
-               "Still finding unique service: %s!" % self.bogussvc
-
-
-class FindAPI(unittest.TestCase):
-    '''Class: FindAPI - class to test the find method of the AImDNS class
-    '''
-    bogussvc = "not_likely_to_exist_service"
-
-    class BogusService(object):
-        '''Class to start and teardown a bogus service.
-        '''
-        dns_sd = "/bin/dns-sd"
+from nose.plugins.skip import SkipTest
 
-        def __init__(self, name, svc_type, domain):
-            '''
-            Start a dns-sd process advertising a service with name, type with
-            svc_type in the domain provided
-            '''
-            self.proc = subprocess.Popen([self.dns_sd, "-R", name,
-                                          svc_type, domain, "9999",
-                                          "foo=bar"],
-                                         stdout=subprocess.PIPE,
-                                         stderr=subprocess.STDOUT)
-
-        def __del__(self):
-            '''
-            Kill process on object deletion -- remember to hold object in a
-            variable or this will get called right after creation
-            '''
-            self.proc.terminate()
-            # wait for dns-sd to die
-            time.sleep(0.5)
-
-    def test_find(self):
-        '''Test AImDNS().find() returns True when service is found and False
-           when not found
-        '''
-        mdns = aimdns.AImDNS()
-        mdns.timeout = 2
-        # negative test
-        assert mdns.find(servicename=self.bogussvc) == False, \
-               "Found bogus service: %s!" % self.bogussvc
-
-        # start-up service for a positive test
-        # pylint: disable-msg=W0212
-        bogosvc = self.BogusService(self.bogussvc, common.REGTYPE, mdns.domain)
-        # pylint: enable-msg=W0212
-        assert mdns.find(self.bogussvc) == True, \
-               "Failed to find unique service: %s!" % self.bogussvc
-        del(bogosvc)
-
-    def test_browse(self):
-        '''Test that AImDNS().browse returns True upon finding a service
-        '''
-        mdns = aimdns.AImDNS()
-        mdns.timeout = 2
-        # start up a service to test browse
-        # pylint: disable-msg=W0212
-        bogosvc = self.BogusService(self.bogussvc, common.REGTYPE, mdns.domain)
-        # pylint: enable-msg=W0212
-        assert mdns.browse() == True, "Did not find any services!"
-        del(bogosvc)
-
-    def test_interfaces(self):
-        '''Verify a unique service shows up for all interfaces listed
-        (since dns-sd publishes on all iterfaces) when doing an
-        AImDNS().browse()
-        '''
-        def _in_network(inter_ipv4, networks):
-            '''Ensures that the interface's address is in networks
-            '''
-            # iterate over the network list
-            for network in networks:
-                # check if the interface's IPv4 address is in the network
-                if common.compare_ipv4(inter_ipv4, network):
-                    return True
-            return False
-
-        # services dictionary looks like:
-        #{'e1000g0': [
-        #    {'domain': u'local', 'hosttarget': u'jumprope.local.',
-        #     'comments': 'aiwebserver=10.10.44.5:46501',
-        #     'servicename': u'install_test_ai_x86',
-        #     'flags': True, 'port': 46501},
-        #    {'domain': u'local', 'hosttarget': u'jumprope.local.',
-        #     'comments': 'foo=bar', 'flags': True, 'port': 9999,
-        #     'servicename': u'not_likely_to_exist_service'}
-        #]}
-
-        mdns = aimdns.AImDNS()
-        mdns.timeout = 2
-
-        # start up a service to test browse
-        # pylint: disable-msg=W0212
-        bogosvc = self.BogusService(self.bogussvc, common.REGTYPE, mdns.domain)
-        # pylint: enable-msg=W0212
-
-        assert mdns.browse() == True, "Did not find any services!"
-        for interface in mdns.services:
-            in_net = _in_network(mdns.interfaces[interface], mdns.networks)
-            if (in_net and not mdns.exclude) or (not in_net and mdns.exclude):
-                assert any([svc for svc in mdns.services[interface] if
-                        svc['servicename'] == self.bogussvc]), \
-                        "Unable to find unique service on interface: %s" % \
-                        interface
-        del(bogosvc)
+from solaris_install import CalledProcessError, Popen
 
 
 class RedirectedOutput(object):
@@ -293,6 +120,9 @@
     def test_browse_callback(self):
         '''test browse callback
         '''
+        # Ensure system/install/server SMF service is available
+        check_install_SMF()
+
         mdns = aimdns.AImDNS()
         rtn = mdns._browse_callback(None, None, 0, pyb.kDNSServiceErr_Unknown,
                             self.name, self.regtype, self.domain)
@@ -310,6 +140,7 @@
         sys.stderr = redirected
         # _ needs to get instantiated within the redirected output
         gettext.install("ai", "/usr/lib/locale")
+        mdns._resolved = list()
         mdns._browse_callback(None, None, 0, pyb.kDNSServiceErr_NoError,
                             self.name, self.regtype, self.domain)
         sys.stderr = sys.__stderr__
@@ -381,6 +212,19 @@
                 "_convert_cidr_mask failed for 8 cidr mask"
 
 
+def check_install_SMF():
+    ''' Check if install/server SMF services is available.
+        returning True if available and False if not.
+    '''
+    # Ensure system/install/server SMF service is available
+    cmd = ["/usr/bin/svcs", "svc:/system/install/server"]
+    try:
+        Popen.check_call(cmd, stdout=Popen.DEVNULL, stderr=Popen.DEVNULL)
+    except CalledProcessError:
+        # This system does not have the service so skip the test
+        raise SkipTest("svc:/system/install/server not installed")
+
+
 if __name__ == '__main__':
     gettext.install("ai", "/usr/lib/locale")
     unittest.main()
--- a/usr/src/tools/tests/README	Wed Aug 31 10:25:52 2011 +1000
+++ b/usr/src/tools/tests/README	Wed Aug 31 10:57:23 2011 +0100
@@ -153,6 +153,7 @@
              ai-webserver:  cmd/ai-webserver/test
              auto-install:  cmd/auto-install/checkpoints/test
         auto-install/test:  cmd/auto-install/test
+ auto-install/test/manual:  cmd/auto-install/test/manual
                      boot:  lib/install_boot/test
                    common:  lib/install_common/test
              distro_const:  cmd/distro_const/checkpoints/test
@@ -160,6 +161,7 @@
                    engine:  lib/install_engine/test
                       ict:  lib/install_ict/test
                installadm:  cmd/installadm/test
+        installadm/manual:  cmd/installadm/test/manual
                     js2ai:  cmd/js2ai/modules/test
                 libaimdns:  lib/libaimdns/test
                 liberrsvc:  lib/liberrsvc/test