You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by ma...@apache.org on 2013/02/04 03:24:02 UTC

svn commit: r1442010 [9/29] - in /incubator/ambari/branches/branch-1.2: ./ ambari-agent/ ambari-agent/conf/unix/ ambari-agent/src/examples/ ambari-agent/src/main/puppet/modules/hdp-ganglia/files/ ambari-agent/src/main/puppet/modules/hdp-ganglia/manifes...

Added: incubator/ambari/branches/branch-1.2/ambari-common/src/test/python/mock/tests/testpatch.py
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.2/ambari-common/src/test/python/mock/tests/testpatch.py?rev=1442010&view=auto
==============================================================================
--- incubator/ambari/branches/branch-1.2/ambari-common/src/test/python/mock/tests/testpatch.py (added)
+++ incubator/ambari/branches/branch-1.2/ambari-common/src/test/python/mock/tests/testpatch.py Mon Feb  4 02:23:55 2013
@@ -0,0 +1,1815 @@
+# Copyright (C) 2007-2012 Michael Foord & the mock team
+# E-mail: fuzzyman AT voidspace DOT org DOT uk
+# http://www.voidspace.org.uk/python/mock/
+
+import os
+import sys
+
+from tests import support
+from tests.support import unittest2, inPy3k, SomeClass, is_instance, callable
+
+from mock import (
+    NonCallableMock, CallableMixin, patch, sentinel,
+    MagicMock, Mock, NonCallableMagicMock, patch, _patch,
+    DEFAULT, call, _get_target
+)
+
+builtin_string = '__builtin__'
+if inPy3k:
+    builtin_string = 'builtins'
+    unicode = str
+
+PTModule = sys.modules[__name__]
+MODNAME = '%s.PTModule' % __name__
+
+
+def _get_proxy(obj, get_only=True):
+    class Proxy(object):
+        def __getattr__(self, name):
+            return getattr(obj, name)
+    if not get_only:
+        def __setattr__(self, name, value):
+            setattr(obj, name, value)
+        def __delattr__(self, name):
+            delattr(obj, name)
+        Proxy.__setattr__ = __setattr__
+        Proxy.__delattr__ = __delattr__
+    return Proxy()
+
+
+# for use in the test
+something  = sentinel.Something
+something_else  = sentinel.SomethingElse
+
+
+class Foo(object):
+    def __init__(self, a):
+        pass
+    def f(self, a):
+        pass
+    def g(self):
+        pass
+    foo = 'bar'
+
+    class Bar(object):
+        def a(self):
+            pass
+
+foo_name = '%s.Foo' % __name__
+
+
+def function(a, b=Foo):
+    pass
+
+
+class Container(object):
+    def __init__(self):
+        self.values = {}
+
+    def __getitem__(self, name):
+        return self.values[name]
+
+    def __setitem__(self, name, value):
+        self.values[name] = value
+
+    def __delitem__(self, name):
+        del self.values[name]
+
+    def __iter__(self):
+        return iter(self.values)
+
+
+
+class PatchTest(unittest2.TestCase):
+
+    def assertNotCallable(self, obj, magic=True):
+        MockClass = NonCallableMagicMock
+        if not magic:
+            MockClass = NonCallableMock
+
+        self.assertRaises(TypeError, obj)
+        self.assertTrue(is_instance(obj, MockClass))
+        self.assertFalse(is_instance(obj, CallableMixin))
+
+
+    def test_single_patchobject(self):
+        class Something(object):
+            attribute = sentinel.Original
+
+        @patch.object(Something, 'attribute', sentinel.Patched)
+        def test():
+            self.assertEqual(Something.attribute, sentinel.Patched, "unpatched")
+
+        test()
+        self.assertEqual(Something.attribute, sentinel.Original,
+                         "patch not restored")
+
+
+    def test_patchobject_with_none(self):
+        class Something(object):
+            attribute = sentinel.Original
+
+        @patch.object(Something, 'attribute', None)
+        def test():
+            self.assertIsNone(Something.attribute, "unpatched")
+
+        test()
+        self.assertEqual(Something.attribute, sentinel.Original,
+                         "patch not restored")
+
+
+    def test_multiple_patchobject(self):
+        class Something(object):
+            attribute = sentinel.Original
+            next_attribute = sentinel.Original2
+
+        @patch.object(Something, 'attribute', sentinel.Patched)
+        @patch.object(Something, 'next_attribute', sentinel.Patched2)
+        def test():
+            self.assertEqual(Something.attribute, sentinel.Patched,
+                             "unpatched")
+            self.assertEqual(Something.next_attribute, sentinel.Patched2,
+                             "unpatched")
+
+        test()
+        self.assertEqual(Something.attribute, sentinel.Original,
+                         "patch not restored")
+        self.assertEqual(Something.next_attribute, sentinel.Original2,
+                         "patch not restored")
+
+
+    def test_object_lookup_is_quite_lazy(self):
+        global something
+        original = something
+        @patch('%s.something' % __name__, sentinel.Something2)
+        def test():
+            pass
+
+        try:
+            something = sentinel.replacement_value
+            test()
+            self.assertEqual(something, sentinel.replacement_value)
+        finally:
+            something = original
+
+
+    def test_patch(self):
+        @patch('%s.something' % __name__, sentinel.Something2)
+        def test():
+            self.assertEqual(PTModule.something, sentinel.Something2,
+                             "unpatched")
+
+        test()
+        self.assertEqual(PTModule.something, sentinel.Something,
+                         "patch not restored")
+
+        @patch('%s.something' % __name__, sentinel.Something2)
+        @patch('%s.something_else' % __name__, sentinel.SomethingElse)
+        def test():
+            self.assertEqual(PTModule.something, sentinel.Something2,
+                             "unpatched")
+            self.assertEqual(PTModule.something_else, sentinel.SomethingElse,
+                             "unpatched")
+
+        self.assertEqual(PTModule.something, sentinel.Something,
+                         "patch not restored")
+        self.assertEqual(PTModule.something_else, sentinel.SomethingElse,
+                         "patch not restored")
+
+        # Test the patching and restoring works a second time
+        test()
+
+        self.assertEqual(PTModule.something, sentinel.Something,
+                         "patch not restored")
+        self.assertEqual(PTModule.something_else, sentinel.SomethingElse,
+                         "patch not restored")
+
+        mock = Mock()
+        mock.return_value = sentinel.Handle
+        @patch('%s.open' % builtin_string, mock)
+        def test():
+            self.assertEqual(open('filename', 'r'), sentinel.Handle,
+                             "open not patched")
+        test()
+        test()
+
+        self.assertNotEqual(open, mock, "patch not restored")
+
+
+    def test_patch_class_attribute(self):
+        @patch('%s.SomeClass.class_attribute' % __name__,
+               sentinel.ClassAttribute)
+        def test():
+            self.assertEqual(PTModule.SomeClass.class_attribute,
+                             sentinel.ClassAttribute, "unpatched")
+        test()
+
+        self.assertIsNone(PTModule.SomeClass.class_attribute,
+                          "patch not restored")
+
+
+    def test_patchobject_with_default_mock(self):
+        class Test(object):
+            something = sentinel.Original
+            something2 = sentinel.Original2
+
+        @patch.object(Test, 'something')
+        def test(mock):
+            self.assertEqual(mock, Test.something,
+                             "Mock not passed into test function")
+            self.assertIsInstance(mock, MagicMock,
+                            "patch with two arguments did not create a mock")
+
+        test()
+
+        @patch.object(Test, 'something')
+        @patch.object(Test, 'something2')
+        def test(this1, this2, mock1, mock2):
+            self.assertEqual(this1, sentinel.this1,
+                             "Patched function didn't receive initial argument")
+            self.assertEqual(this2, sentinel.this2,
+                             "Patched function didn't receive second argument")
+            self.assertEqual(mock1, Test.something2,
+                             "Mock not passed into test function")
+            self.assertEqual(mock2, Test.something,
+                             "Second Mock not passed into test function")
+            self.assertIsInstance(mock2, MagicMock,
+                            "patch with two arguments did not create a mock")
+            self.assertIsInstance(mock2, MagicMock,
+                            "patch with two arguments did not create a mock")
+
+            # A hack to test that new mocks are passed the second time
+            self.assertNotEqual(outerMock1, mock1, "unexpected value for mock1")
+            self.assertNotEqual(outerMock2, mock2, "unexpected value for mock1")
+            return mock1, mock2
+
+        outerMock1 = outerMock2 = None
+        outerMock1, outerMock2 = test(sentinel.this1, sentinel.this2)
+
+        # Test that executing a second time creates new mocks
+        test(sentinel.this1, sentinel.this2)
+
+
+    def test_patch_with_spec(self):
+        @patch('%s.SomeClass' % __name__, spec=SomeClass)
+        def test(MockSomeClass):
+            self.assertEqual(SomeClass, MockSomeClass)
+            self.assertTrue(is_instance(SomeClass.wibble, MagicMock))
+            self.assertRaises(AttributeError, lambda: SomeClass.not_wibble)
+
+        test()
+
+
+    def test_patchobject_with_spec(self):
+        @patch.object(SomeClass, 'class_attribute', spec=SomeClass)
+        def test(MockAttribute):
+            self.assertEqual(SomeClass.class_attribute, MockAttribute)
+            self.assertTrue(is_instance(SomeClass.class_attribute.wibble,
+                                       MagicMock))
+            self.assertRaises(AttributeError,
+                              lambda: SomeClass.class_attribute.not_wibble)
+
+        test()
+
+
+    def test_patch_with_spec_as_list(self):
+        @patch('%s.SomeClass' % __name__, spec=['wibble'])
+        def test(MockSomeClass):
+            self.assertEqual(SomeClass, MockSomeClass)
+            self.assertTrue(is_instance(SomeClass.wibble, MagicMock))
+            self.assertRaises(AttributeError, lambda: SomeClass.not_wibble)
+
+        test()
+
+
+    def test_patchobject_with_spec_as_list(self):
+        @patch.object(SomeClass, 'class_attribute', spec=['wibble'])
+        def test(MockAttribute):
+            self.assertEqual(SomeClass.class_attribute, MockAttribute)
+            self.assertTrue(is_instance(SomeClass.class_attribute.wibble,
+                                       MagicMock))
+            self.assertRaises(AttributeError,
+                              lambda: SomeClass.class_attribute.not_wibble)
+
+        test()
+
+
+    def test_nested_patch_with_spec_as_list(self):
+        # regression test for nested decorators
+        @patch('%s.open' % builtin_string)
+        @patch('%s.SomeClass' % __name__, spec=['wibble'])
+        def test(MockSomeClass, MockOpen):
+            self.assertEqual(SomeClass, MockSomeClass)
+            self.assertTrue(is_instance(SomeClass.wibble, MagicMock))
+            self.assertRaises(AttributeError, lambda: SomeClass.not_wibble)
+        test()
+
+
+    def test_patch_with_spec_as_boolean(self):
+        @patch('%s.SomeClass' % __name__, spec=True)
+        def test(MockSomeClass):
+            self.assertEqual(SomeClass, MockSomeClass)
+            # Should not raise attribute error
+            MockSomeClass.wibble
+
+            self.assertRaises(AttributeError, lambda: MockSomeClass.not_wibble)
+
+        test()
+
+
+    def test_patch_object_with_spec_as_boolean(self):
+        @patch.object(PTModule, 'SomeClass', spec=True)
+        def test(MockSomeClass):
+            self.assertEqual(SomeClass, MockSomeClass)
+            # Should not raise attribute error
+            MockSomeClass.wibble
+
+            self.assertRaises(AttributeError, lambda: MockSomeClass.not_wibble)
+
+        test()
+
+
+    def test_patch_class_acts_with_spec_is_inherited(self):
+        @patch('%s.SomeClass' % __name__, spec=True)
+        def test(MockSomeClass):
+            self.assertTrue(is_instance(MockSomeClass, MagicMock))
+            instance = MockSomeClass()
+            self.assertNotCallable(instance)
+            # Should not raise attribute error
+            instance.wibble
+
+            self.assertRaises(AttributeError, lambda: instance.not_wibble)
+
+        test()
+
+
+    def test_patch_with_create_mocks_non_existent_attributes(self):
+        @patch('%s.frooble' % builtin_string, sentinel.Frooble, create=True)
+        def test():
+            self.assertEqual(frooble, sentinel.Frooble)
+
+        test()
+        self.assertRaises(NameError, lambda: frooble)
+
+
+    def test_patchobject_with_create_mocks_non_existent_attributes(self):
+        @patch.object(SomeClass, 'frooble', sentinel.Frooble, create=True)
+        def test():
+            self.assertEqual(SomeClass.frooble, sentinel.Frooble)
+
+        test()
+        self.assertFalse(hasattr(SomeClass, 'frooble'))
+
+
+    def test_patch_wont_create_by_default(self):
+        try:
+            @patch('%s.frooble' % builtin_string, sentinel.Frooble)
+            def test():
+                self.assertEqual(frooble, sentinel.Frooble)
+
+            test()
+        except AttributeError:
+            pass
+        else:
+            self.fail('Patching non existent attributes should fail')
+
+        self.assertRaises(NameError, lambda: frooble)
+
+
+    def test_patchobject_wont_create_by_default(self):
+        try:
+            @patch.object(SomeClass, 'frooble', sentinel.Frooble)
+            def test():
+                self.fail('Patching non existent attributes should fail')
+
+            test()
+        except AttributeError:
+            pass
+        else:
+            self.fail('Patching non existent attributes should fail')
+        self.assertFalse(hasattr(SomeClass, 'frooble'))
+
+
+    def test_patch_with_static_methods(self):
+        class Foo(object):
+            @staticmethod
+            def woot():
+                return sentinel.Static
+
+        @patch.object(Foo, 'woot', staticmethod(lambda: sentinel.Patched))
+        def anonymous():
+            self.assertEqual(Foo.woot(), sentinel.Patched)
+        anonymous()
+
+        self.assertEqual(Foo.woot(), sentinel.Static)
+
+
+    def test_patch_local(self):
+        foo = sentinel.Foo
+        @patch.object(sentinel, 'Foo', 'Foo')
+        def anonymous():
+            self.assertEqual(sentinel.Foo, 'Foo')
+        anonymous()
+
+        self.assertEqual(sentinel.Foo, foo)
+
+
+    def test_patch_slots(self):
+        class Foo(object):
+            __slots__ = ('Foo',)
+
+        foo = Foo()
+        foo.Foo = sentinel.Foo
+
+        @patch.object(foo, 'Foo', 'Foo')
+        def anonymous():
+            self.assertEqual(foo.Foo, 'Foo')
+        anonymous()
+
+        self.assertEqual(foo.Foo, sentinel.Foo)
+
+
+    def test_patchobject_class_decorator(self):
+        class Something(object):
+            attribute = sentinel.Original
+
+        class Foo(object):
+            def test_method(other_self):
+                self.assertEqual(Something.attribute, sentinel.Patched,
+                                 "unpatched")
+            def not_test_method(other_self):
+                self.assertEqual(Something.attribute, sentinel.Original,
+                                 "non-test method patched")
+
+        Foo = patch.object(Something, 'attribute', sentinel.Patched)(Foo)
+
+        f = Foo()
+        f.test_method()
+        f.not_test_method()
+
+        self.assertEqual(Something.attribute, sentinel.Original,
+                         "patch not restored")
+
+
+    def test_patch_class_decorator(self):
+        class Something(object):
+            attribute = sentinel.Original
+
+        class Foo(object):
+            def test_method(other_self, mock_something):
+                self.assertEqual(PTModule.something, mock_something,
+                                 "unpatched")
+            def not_test_method(other_self):
+                self.assertEqual(PTModule.something, sentinel.Something,
+                                 "non-test method patched")
+        Foo = patch('%s.something' % __name__)(Foo)
+
+        f = Foo()
+        f.test_method()
+        f.not_test_method()
+
+        self.assertEqual(Something.attribute, sentinel.Original,
+                         "patch not restored")
+        self.assertEqual(PTModule.something, sentinel.Something,
+                         "patch not restored")
+
+
+    def test_patchobject_twice(self):
+        class Something(object):
+            attribute = sentinel.Original
+            next_attribute = sentinel.Original2
+
+        @patch.object(Something, 'attribute', sentinel.Patched)
+        @patch.object(Something, 'attribute', sentinel.Patched)
+        def test():
+            self.assertEqual(Something.attribute, sentinel.Patched, "unpatched")
+
+        test()
+
+        self.assertEqual(Something.attribute, sentinel.Original,
+                         "patch not restored")
+
+
+    def test_patch_dict(self):
+        foo = {'initial': object(), 'other': 'something'}
+        original = foo.copy()
+
+        @patch.dict(foo)
+        def test():
+            foo['a'] = 3
+            del foo['initial']
+            foo['other'] = 'something else'
+
+        test()
+
+        self.assertEqual(foo, original)
+
+        @patch.dict(foo, {'a': 'b'})
+        def test():
+            self.assertEqual(len(foo), 3)
+            self.assertEqual(foo['a'], 'b')
+
+        test()
+
+        self.assertEqual(foo, original)
+
+        @patch.dict(foo, [('a', 'b')])
+        def test():
+            self.assertEqual(len(foo), 3)
+            self.assertEqual(foo['a'], 'b')
+
+        test()
+
+        self.assertEqual(foo, original)
+
+
+    def test_patch_dict_with_container_object(self):
+        foo = Container()
+        foo['initial'] = object()
+        foo['other'] =  'something'
+
+        original = foo.values.copy()
+
+        @patch.dict(foo)
+        def test():
+            foo['a'] = 3
+            del foo['initial']
+            foo['other'] = 'something else'
+
+        test()
+
+        self.assertEqual(foo.values, original)
+
+        @patch.dict(foo, {'a': 'b'})
+        def test():
+            self.assertEqual(len(foo.values), 3)
+            self.assertEqual(foo['a'], 'b')
+
+        test()
+
+        self.assertEqual(foo.values, original)
+
+
+    def test_patch_dict_with_clear(self):
+        foo = {'initial': object(), 'other': 'something'}
+        original = foo.copy()
+
+        @patch.dict(foo, clear=True)
+        def test():
+            self.assertEqual(foo, {})
+            foo['a'] = 3
+            foo['other'] = 'something else'
+
+        test()
+
+        self.assertEqual(foo, original)
+
+        @patch.dict(foo, {'a': 'b'}, clear=True)
+        def test():
+            self.assertEqual(foo, {'a': 'b'})
+
+        test()
+
+        self.assertEqual(foo, original)
+
+        @patch.dict(foo, [('a', 'b')], clear=True)
+        def test():
+            self.assertEqual(foo, {'a': 'b'})
+
+        test()
+
+        self.assertEqual(foo, original)
+
+
+    def test_patch_dict_with_container_object_and_clear(self):
+        foo = Container()
+        foo['initial'] = object()
+        foo['other'] =  'something'
+
+        original = foo.values.copy()
+
+        @patch.dict(foo, clear=True)
+        def test():
+            self.assertEqual(foo.values, {})
+            foo['a'] = 3
+            foo['other'] = 'something else'
+
+        test()
+
+        self.assertEqual(foo.values, original)
+
+        @patch.dict(foo, {'a': 'b'}, clear=True)
+        def test():
+            self.assertEqual(foo.values, {'a': 'b'})
+
+        test()
+
+        self.assertEqual(foo.values, original)
+
+
+    def test_name_preserved(self):
+        foo = {}
+
+        @patch('%s.SomeClass' % __name__, object())
+        @patch('%s.SomeClass' % __name__, object(), autospec=True)
+        @patch.object(SomeClass, object())
+        @patch.dict(foo)
+        def some_name():
+            pass
+
+        self.assertEqual(some_name.__name__, 'some_name')
+
+
+    def test_patch_with_exception(self):
+        foo = {}
+
+        @patch.dict(foo, {'a': 'b'})
+        def test():
+            raise NameError('Konrad')
+        try:
+            test()
+        except NameError:
+            pass
+        else:
+            self.fail('NameError not raised by test')
+
+        self.assertEqual(foo, {})
+
+
+    def test_patch_dict_with_string(self):
+        @patch.dict('os.environ', {'konrad_delong': 'some value'})
+        def test():
+            self.assertIn('konrad_delong', os.environ)
+
+        test()
+
+
+    @unittest2.expectedFailure
+    def test_patch_descriptor(self):
+        # would be some effort to fix this - we could special case the
+        # builtin descriptors: classmethod, property, staticmethod
+        class Nothing(object):
+            foo = None
+
+        class Something(object):
+            foo = {}
+
+            @patch.object(Nothing, 'foo', 2)
+            @classmethod
+            def klass(cls):
+                self.assertIs(cls, Something)
+
+            @patch.object(Nothing, 'foo', 2)
+            @staticmethod
+            def static(arg):
+                return arg
+
+            @patch.dict(foo)
+            @classmethod
+            def klass_dict(cls):
+                self.assertIs(cls, Something)
+
+            @patch.dict(foo)
+            @staticmethod
+            def static_dict(arg):
+                return arg
+
+        # these will raise exceptions if patching descriptors is broken
+        self.assertEqual(Something.static('f00'), 'f00')
+        Something.klass()
+        self.assertEqual(Something.static_dict('f00'), 'f00')
+        Something.klass_dict()
+
+        something = Something()
+        self.assertEqual(something.static('f00'), 'f00')
+        something.klass()
+        self.assertEqual(something.static_dict('f00'), 'f00')
+        something.klass_dict()
+
+
+    def test_patch_spec_set(self):
+        @patch('%s.SomeClass' % __name__, spec_set=SomeClass)
+        def test(MockClass):
+            MockClass.z = 'foo'
+
+        self.assertRaises(AttributeError, test)
+
+        @patch.object(support, 'SomeClass', spec_set=SomeClass)
+        def test(MockClass):
+            MockClass.z = 'foo'
+
+        self.assertRaises(AttributeError, test)
+        @patch('%s.SomeClass' % __name__, spec_set=True)
+        def test(MockClass):
+            MockClass.z = 'foo'
+
+        self.assertRaises(AttributeError, test)
+
+        @patch.object(support, 'SomeClass', spec_set=True)
+        def test(MockClass):
+            MockClass.z = 'foo'
+
+        self.assertRaises(AttributeError, test)
+
+
+    def test_spec_set_inherit(self):
+        @patch('%s.SomeClass' % __name__, spec_set=True)
+        def test(MockClass):
+            instance = MockClass()
+            instance.z = 'foo'
+
+        self.assertRaises(AttributeError, test)
+
+
+    def test_patch_start_stop(self):
+        original = something
+        patcher = patch('%s.something' % __name__)
+        self.assertIs(something, original)
+        mock = patcher.start()
+        try:
+            self.assertIsNot(mock, original)
+            self.assertIs(something, mock)
+        finally:
+            patcher.stop()
+        self.assertIs(something, original)
+
+
+    def test_stop_without_start(self):
+        patcher = patch(foo_name, 'bar', 3)
+
+        # calling stop without start used to produce a very obscure error
+        self.assertRaises(RuntimeError, patcher.stop)
+
+
+    def test_patchobject_start_stop(self):
+        original = something
+        patcher = patch.object(PTModule, 'something', 'foo')
+        self.assertIs(something, original)
+        replaced = patcher.start()
+        try:
+            self.assertEqual(replaced, 'foo')
+            self.assertIs(something, replaced)
+        finally:
+            patcher.stop()
+        self.assertIs(something, original)
+
+
+    def test_patch_dict_start_stop(self):
+        d = {'foo': 'bar'}
+        original = d.copy()
+        patcher = patch.dict(d, [('spam', 'eggs')], clear=True)
+        self.assertEqual(d, original)
+
+        patcher.start()
+        try:
+            self.assertEqual(d, {'spam': 'eggs'})
+        finally:
+            patcher.stop()
+        self.assertEqual(d, original)
+
+
+    def test_patch_dict_class_decorator(self):
+        this = self
+        d = {'spam': 'eggs'}
+        original = d.copy()
+
+        class Test(object):
+            def test_first(self):
+                this.assertEqual(d, {'foo': 'bar'})
+            def test_second(self):
+                this.assertEqual(d, {'foo': 'bar'})
+
+        Test = patch.dict(d, {'foo': 'bar'}, clear=True)(Test)
+        self.assertEqual(d, original)
+
+        test = Test()
+
+        test.test_first()
+        self.assertEqual(d, original)
+
+        test.test_second()
+        self.assertEqual(d, original)
+
+        test = Test()
+
+        test.test_first()
+        self.assertEqual(d, original)
+
+        test.test_second()
+        self.assertEqual(d, original)
+
+
+    def test_get_only_proxy(self):
+        class Something(object):
+            foo = 'foo'
+        class SomethingElse:
+            foo = 'foo'
+
+        for thing in Something, SomethingElse, Something(), SomethingElse:
+            proxy = _get_proxy(thing)
+
+            @patch.object(proxy, 'foo', 'bar')
+            def test():
+                self.assertEqual(proxy.foo, 'bar')
+            test()
+            self.assertEqual(proxy.foo, 'foo')
+            self.assertEqual(thing.foo, 'foo')
+            self.assertNotIn('foo', proxy.__dict__)
+
+
+    def test_get_set_delete_proxy(self):
+        class Something(object):
+            foo = 'foo'
+        class SomethingElse:
+            foo = 'foo'
+
+        for thing in Something, SomethingElse, Something(), SomethingElse:
+            proxy = _get_proxy(Something, get_only=False)
+
+            @patch.object(proxy, 'foo', 'bar')
+            def test():
+                self.assertEqual(proxy.foo, 'bar')
+            test()
+            self.assertEqual(proxy.foo, 'foo')
+            self.assertEqual(thing.foo, 'foo')
+            self.assertNotIn('foo', proxy.__dict__)
+
+
+    def test_patch_keyword_args(self):
+        kwargs = {'side_effect': KeyError, 'foo.bar.return_value': 33,
+                  'foo': MagicMock()}
+
+        patcher = patch(foo_name, **kwargs)
+        mock = patcher.start()
+        patcher.stop()
+
+        self.assertRaises(KeyError, mock)
+        self.assertEqual(mock.foo.bar(), 33)
+        self.assertIsInstance(mock.foo, MagicMock)
+
+
+    def test_patch_object_keyword_args(self):
+        kwargs = {'side_effect': KeyError, 'foo.bar.return_value': 33,
+                  'foo': MagicMock()}
+
+        patcher = patch.object(Foo, 'f', **kwargs)
+        mock = patcher.start()
+        patcher.stop()
+
+        self.assertRaises(KeyError, mock)
+        self.assertEqual(mock.foo.bar(), 33)
+        self.assertIsInstance(mock.foo, MagicMock)
+
+
+    def test_patch_dict_keyword_args(self):
+        original = {'foo': 'bar'}
+        copy = original.copy()
+
+        patcher = patch.dict(original, foo=3, bar=4, baz=5)
+        patcher.start()
+
+        try:
+            self.assertEqual(original, dict(foo=3, bar=4, baz=5))
+        finally:
+            patcher.stop()
+
+        self.assertEqual(original, copy)
+
+
+    def test_autospec(self):
+        class Boo(object):
+            def __init__(self, a):
+                pass
+            def f(self, a):
+                pass
+            def g(self):
+                pass
+            foo = 'bar'
+
+            class Bar(object):
+                def a(self):
+                    pass
+
+        def _test(mock):
+            mock(1)
+            mock.assert_called_with(1)
+            self.assertRaises(TypeError, mock)
+
+        def _test2(mock):
+            mock.f(1)
+            mock.f.assert_called_with(1)
+            self.assertRaises(TypeError, mock.f)
+
+            mock.g()
+            mock.g.assert_called_with()
+            self.assertRaises(TypeError, mock.g, 1)
+
+            self.assertRaises(AttributeError, getattr, mock, 'h')
+
+            mock.foo.lower()
+            mock.foo.lower.assert_called_with()
+            self.assertRaises(AttributeError, getattr, mock.foo, 'bar')
+
+            mock.Bar()
+            mock.Bar.assert_called_with()
+
+            mock.Bar.a()
+            mock.Bar.a.assert_called_with()
+            self.assertRaises(TypeError, mock.Bar.a, 1)
+
+            mock.Bar().a()
+            mock.Bar().a.assert_called_with()
+            self.assertRaises(TypeError, mock.Bar().a, 1)
+
+            self.assertRaises(AttributeError, getattr, mock.Bar, 'b')
+            self.assertRaises(AttributeError, getattr, mock.Bar(), 'b')
+
+        def function(mock):
+            _test(mock)
+            _test2(mock)
+            _test2(mock(1))
+            self.assertIs(mock, Foo)
+            return mock
+
+        test = patch(foo_name, autospec=True)(function)
+
+        mock = test()
+        self.assertIsNot(Foo, mock)
+        # test patching a second time works
+        test()
+
+        module = sys.modules[__name__]
+        test = patch.object(module, 'Foo', autospec=True)(function)
+
+        mock = test()
+        self.assertIsNot(Foo, mock)
+        # test patching a second time works
+        test()
+
+
+    def test_autospec_function(self):
+        @patch('%s.function' % __name__, autospec=True)
+        def test(mock):
+            function(1)
+            function.assert_called_with(1)
+            function(2, 3)
+            function.assert_called_with(2, 3)
+
+            self.assertRaises(TypeError, function)
+            self.assertRaises(AttributeError, getattr, function, 'foo')
+
+        test()
+
+
+    def test_autospec_keywords(self):
+        @patch('%s.function' % __name__, autospec=True,
+               return_value=3)
+        def test(mock_function):
+            #self.assertEqual(function.abc, 'foo')
+            return function(1, 2)
+
+        result = test()
+        self.assertEqual(result, 3)
+
+
+    def test_autospec_with_new(self):
+        patcher = patch('%s.function' % __name__, new=3, autospec=True)
+        self.assertRaises(TypeError, patcher.start)
+
+        module = sys.modules[__name__]
+        patcher = patch.object(module, 'function', new=3, autospec=True)
+        self.assertRaises(TypeError, patcher.start)
+
+
+    def test_autospec_with_object(self):
+        class Bar(Foo):
+            extra = []
+
+        patcher = patch(foo_name, autospec=Bar)
+        mock = patcher.start()
+        try:
+            self.assertIsInstance(mock, Bar)
+            self.assertIsInstance(mock.extra, list)
+        finally:
+            patcher.stop()
+
+
+    def test_autospec_inherits(self):
+        FooClass = Foo
+        patcher = patch(foo_name, autospec=True)
+        mock = patcher.start()
+        try:
+            self.assertIsInstance(mock, FooClass)
+            self.assertIsInstance(mock(3), FooClass)
+        finally:
+            patcher.stop()
+
+
+    def test_autospec_name(self):
+        patcher = patch(foo_name, autospec=True)
+        mock = patcher.start()
+
+        try:
+            self.assertIn(" name='Foo'", repr(mock))
+            self.assertIn(" name='Foo.f'", repr(mock.f))
+            self.assertIn(" name='Foo()'", repr(mock(None)))
+            self.assertIn(" name='Foo().f'", repr(mock(None).f))
+        finally:
+            patcher.stop()
+
+
+    def test_tracebacks(self):
+        @patch.object(Foo, 'f', object())
+        def test():
+            raise AssertionError
+        try:
+            test()
+        except:
+            err = sys.exc_info()
+
+        result = unittest2.TextTestResult(None, None, 0)
+        traceback = result._exc_info_to_string(err, self)
+        self.assertIn('raise AssertionError', traceback)
+
+
+    def test_new_callable_patch(self):
+        patcher = patch(foo_name, new_callable=NonCallableMagicMock)
+
+        m1 = patcher.start()
+        patcher.stop()
+        m2 = patcher.start()
+        patcher.stop()
+
+        self.assertIsNot(m1, m2)
+        for mock in m1, m2:
+            self.assertNotCallable(m1)
+
+
+    def test_new_callable_patch_object(self):
+        patcher = patch.object(Foo, 'f', new_callable=NonCallableMagicMock)
+
+        m1 = patcher.start()
+        patcher.stop()
+        m2 = patcher.start()
+        patcher.stop()
+
+        self.assertIsNot(m1, m2)
+        for mock in m1, m2:
+            self.assertNotCallable(m1)
+
+
+    def test_new_callable_keyword_arguments(self):
+        class Bar(object):
+            kwargs = None
+            def __init__(self, **kwargs):
+                Bar.kwargs = kwargs
+
+        patcher = patch(foo_name, new_callable=Bar, arg1=1, arg2=2)
+        m = patcher.start()
+        try:
+            self.assertIs(type(m), Bar)
+            self.assertEqual(Bar.kwargs, dict(arg1=1, arg2=2))
+        finally:
+            patcher.stop()
+
+
+    def test_new_callable_spec(self):
+        class Bar(object):
+            kwargs = None
+            def __init__(self, **kwargs):
+                Bar.kwargs = kwargs
+
+        patcher = patch(foo_name, new_callable=Bar, spec=Bar)
+        patcher.start()
+        try:
+            self.assertEqual(Bar.kwargs, dict(spec=Bar))
+        finally:
+            patcher.stop()
+
+        patcher = patch(foo_name, new_callable=Bar, spec_set=Bar)
+        patcher.start()
+        try:
+            self.assertEqual(Bar.kwargs, dict(spec_set=Bar))
+        finally:
+            patcher.stop()
+
+
+    def test_new_callable_create(self):
+        non_existent_attr = '%s.weeeee' % foo_name
+        p = patch(non_existent_attr, new_callable=NonCallableMock)
+        self.assertRaises(AttributeError, p.start)
+
+        p = patch(non_existent_attr, new_callable=NonCallableMock,
+                  create=True)
+        m = p.start()
+        try:
+            self.assertNotCallable(m, magic=False)
+        finally:
+            p.stop()
+
+
+    def test_new_callable_incompatible_with_new(self):
+        self.assertRaises(
+            ValueError, patch, foo_name, new=object(), new_callable=MagicMock
+        )
+        self.assertRaises(
+            ValueError, patch.object, Foo, 'f', new=object(),
+            new_callable=MagicMock
+        )
+
+
+    def test_new_callable_incompatible_with_autospec(self):
+        self.assertRaises(
+            ValueError, patch, foo_name, new_callable=MagicMock,
+            autospec=True
+        )
+        self.assertRaises(
+            ValueError, patch.object, Foo, 'f', new_callable=MagicMock,
+            autospec=True
+        )
+
+
+    def test_new_callable_inherit_for_mocks(self):
+        class MockSub(Mock):
+            pass
+
+        MockClasses = (
+            NonCallableMock, NonCallableMagicMock, MagicMock, Mock, MockSub
+        )
+        for Klass in MockClasses:
+            for arg in 'spec', 'spec_set':
+                kwargs = {arg: True}
+                p = patch(foo_name, new_callable=Klass, **kwargs)
+                m = p.start()
+                try:
+                    instance = m.return_value
+                    self.assertRaises(AttributeError, getattr, instance, 'x')
+                finally:
+                    p.stop()
+
+
+    def test_new_callable_inherit_non_mock(self):
+        class NotAMock(object):
+            def __init__(self, spec):
+                self.spec = spec
+
+        p = patch(foo_name, new_callable=NotAMock, spec=True)
+        m = p.start()
+        try:
+            self.assertTrue(is_instance(m, NotAMock))
+            self.assertRaises(AttributeError, getattr, m, 'return_value')
+        finally:
+            p.stop()
+
+        self.assertEqual(m.spec, Foo)
+
+
+    def test_new_callable_class_decorating(self):
+        test = self
+        original = Foo
+        class SomeTest(object):
+
+            def _test(self, mock_foo):
+                test.assertIsNot(Foo, original)
+                test.assertIs(Foo, mock_foo)
+                test.assertIsInstance(Foo, SomeClass)
+
+            def test_two(self, mock_foo):
+                self._test(mock_foo)
+            def test_one(self, mock_foo):
+                self._test(mock_foo)
+
+        SomeTest = patch(foo_name, new_callable=SomeClass)(SomeTest)
+        SomeTest().test_one()
+        SomeTest().test_two()
+        self.assertIs(Foo, original)
+
+
+    def test_patch_multiple(self):
+        original_foo = Foo
+        original_f = Foo.f
+        original_g = Foo.g
+
+        patcher1 = patch.multiple(foo_name, f=1, g=2)
+        patcher2 = patch.multiple(Foo, f=1, g=2)
+
+        for patcher in patcher1, patcher2:
+            patcher.start()
+            try:
+                self.assertIs(Foo, original_foo)
+                self.assertEqual(Foo.f, 1)
+                self.assertEqual(Foo.g, 2)
+            finally:
+                patcher.stop()
+
+            self.assertIs(Foo, original_foo)
+            self.assertEqual(Foo.f, original_f)
+            self.assertEqual(Foo.g, original_g)
+
+
+        @patch.multiple(foo_name, f=3, g=4)
+        def test():
+            self.assertIs(Foo, original_foo)
+            self.assertEqual(Foo.f, 3)
+            self.assertEqual(Foo.g, 4)
+
+        test()
+
+
+    def test_patch_multiple_no_kwargs(self):
+        self.assertRaises(ValueError, patch.multiple, foo_name)
+        self.assertRaises(ValueError, patch.multiple, Foo)
+
+
+    def test_patch_multiple_create_mocks(self):
+        original_foo = Foo
+        original_f = Foo.f
+        original_g = Foo.g
+
+        @patch.multiple(foo_name, f=DEFAULT, g=3, foo=DEFAULT)
+        def test(f, foo):
+            self.assertIs(Foo, original_foo)
+            self.assertIs(Foo.f, f)
+            self.assertEqual(Foo.g, 3)
+            self.assertIs(Foo.foo, foo)
+            self.assertTrue(is_instance(f, MagicMock))
+            self.assertTrue(is_instance(foo, MagicMock))
+
+        test()
+        self.assertEqual(Foo.f, original_f)
+        self.assertEqual(Foo.g, original_g)
+
+
+    def test_patch_multiple_create_mocks_different_order(self):
+        # bug revealed by Jython!
+        original_f = Foo.f
+        original_g = Foo.g
+
+        patcher = patch.object(Foo, 'f', 3)
+        patcher.attribute_name = 'f'
+
+        other = patch.object(Foo, 'g', DEFAULT)
+        other.attribute_name = 'g'
+        patcher.additional_patchers = [other]
+
+        @patcher
+        def test(g):
+            self.assertIs(Foo.g, g)
+            self.assertEqual(Foo.f, 3)
+
+        test()
+        self.assertEqual(Foo.f, original_f)
+        self.assertEqual(Foo.g, original_g)
+
+
+    def test_patch_multiple_stacked_decorators(self):
+        original_foo = Foo
+        original_f = Foo.f
+        original_g = Foo.g
+
+        @patch.multiple(foo_name, f=DEFAULT)
+        @patch.multiple(foo_name, foo=DEFAULT)
+        @patch(foo_name + '.g')
+        def test1(g, **kwargs):
+            _test(g, **kwargs)
+
+        @patch.multiple(foo_name, f=DEFAULT)
+        @patch(foo_name + '.g')
+        @patch.multiple(foo_name, foo=DEFAULT)
+        def test2(g, **kwargs):
+            _test(g, **kwargs)
+
+        @patch(foo_name + '.g')
+        @patch.multiple(foo_name, f=DEFAULT)
+        @patch.multiple(foo_name, foo=DEFAULT)
+        def test3(g, **kwargs):
+            _test(g, **kwargs)
+
+        def _test(g, **kwargs):
+            f = kwargs.pop('f')
+            foo = kwargs.pop('foo')
+            self.assertFalse(kwargs)
+
+            self.assertIs(Foo, original_foo)
+            self.assertIs(Foo.f, f)
+            self.assertIs(Foo.g, g)
+            self.assertIs(Foo.foo, foo)
+            self.assertTrue(is_instance(f, MagicMock))
+            self.assertTrue(is_instance(g, MagicMock))
+            self.assertTrue(is_instance(foo, MagicMock))
+
+        test1()
+        test2()
+        test3()
+        self.assertEqual(Foo.f, original_f)
+        self.assertEqual(Foo.g, original_g)
+
+
+    def test_patch_multiple_create_mocks_patcher(self):
+        original_foo = Foo
+        original_f = Foo.f
+        original_g = Foo.g
+
+        patcher = patch.multiple(foo_name, f=DEFAULT, g=3, foo=DEFAULT)
+
+        result = patcher.start()
+        try:
+            f = result['f']
+            foo = result['foo']
+            self.assertEqual(set(result), set(['f', 'foo']))
+
+            self.assertIs(Foo, original_foo)
+            self.assertIs(Foo.f, f)
+            self.assertIs(Foo.foo, foo)
+            self.assertTrue(is_instance(f, MagicMock))
+            self.assertTrue(is_instance(foo, MagicMock))
+        finally:
+            patcher.stop()
+
+        self.assertEqual(Foo.f, original_f)
+        self.assertEqual(Foo.g, original_g)
+
+
+    def test_patch_multiple_decorating_class(self):
+        test = self
+        original_foo = Foo
+        original_f = Foo.f
+        original_g = Foo.g
+
+        class SomeTest(object):
+
+            def _test(self, f, foo):
+                test.assertIs(Foo, original_foo)
+                test.assertIs(Foo.f, f)
+                test.assertEqual(Foo.g, 3)
+                test.assertIs(Foo.foo, foo)
+                test.assertTrue(is_instance(f, MagicMock))
+                test.assertTrue(is_instance(foo, MagicMock))
+
+            def test_two(self, f, foo):
+                self._test(f, foo)
+            def test_one(self, f, foo):
+                self._test(f, foo)
+
+        SomeTest = patch.multiple(
+            foo_name, f=DEFAULT, g=3, foo=DEFAULT
+        )(SomeTest)
+
+        thing = SomeTest()
+        thing.test_one()
+        thing.test_two()
+
+        self.assertEqual(Foo.f, original_f)
+        self.assertEqual(Foo.g, original_g)
+
+
+    def test_patch_multiple_create(self):
+        patcher = patch.multiple(Foo, blam='blam')
+        self.assertRaises(AttributeError, patcher.start)
+
+        patcher = patch.multiple(Foo, blam='blam', create=True)
+        patcher.start()
+        try:
+            self.assertEqual(Foo.blam, 'blam')
+        finally:
+            patcher.stop()
+
+        self.assertFalse(hasattr(Foo, 'blam'))
+
+
+    def test_patch_multiple_spec_set(self):
+        # if spec_set works then we can assume that spec and autospec also
+        # work as the underlying machinery is the same
+        patcher = patch.multiple(Foo, foo=DEFAULT, spec_set=['a', 'b'])
+        result = patcher.start()
+        try:
+            self.assertEqual(Foo.foo, result['foo'])
+            Foo.foo.a(1)
+            Foo.foo.b(2)
+            Foo.foo.a.assert_called_with(1)
+            Foo.foo.b.assert_called_with(2)
+            self.assertRaises(AttributeError, setattr, Foo.foo, 'c', None)
+        finally:
+            patcher.stop()
+
+
+    def test_patch_multiple_new_callable(self):
+        class Thing(object):
+            pass
+
+        patcher = patch.multiple(
+            Foo, f=DEFAULT, g=DEFAULT, new_callable=Thing
+        )
+        result = patcher.start()
+        try:
+            self.assertIs(Foo.f, result['f'])
+            self.assertIs(Foo.g, result['g'])
+            self.assertIsInstance(Foo.f, Thing)
+            self.assertIsInstance(Foo.g, Thing)
+            self.assertIsNot(Foo.f, Foo.g)
+        finally:
+            patcher.stop()
+
+
+    def test_nested_patch_failure(self):
+        original_f = Foo.f
+        original_g = Foo.g
+
+        @patch.object(Foo, 'g', 1)
+        @patch.object(Foo, 'missing', 1)
+        @patch.object(Foo, 'f', 1)
+        def thing1():
+            pass
+
+        @patch.object(Foo, 'missing', 1)
+        @patch.object(Foo, 'g', 1)
+        @patch.object(Foo, 'f', 1)
+        def thing2():
+            pass
+
+        @patch.object(Foo, 'g', 1)
+        @patch.object(Foo, 'f', 1)
+        @patch.object(Foo, 'missing', 1)
+        def thing3():
+            pass
+
+        for func in thing1, thing2, thing3:
+            self.assertRaises(AttributeError, func)
+            self.assertEqual(Foo.f, original_f)
+            self.assertEqual(Foo.g, original_g)
+
+
+    def test_new_callable_failure(self):
+        original_f = Foo.f
+        original_g = Foo.g
+        original_foo = Foo.foo
+
+        def crasher():
+            raise NameError('crasher')
+
+        @patch.object(Foo, 'g', 1)
+        @patch.object(Foo, 'foo', new_callable=crasher)
+        @patch.object(Foo, 'f', 1)
+        def thing1():
+            pass
+
+        @patch.object(Foo, 'foo', new_callable=crasher)
+        @patch.object(Foo, 'g', 1)
+        @patch.object(Foo, 'f', 1)
+        def thing2():
+            pass
+
+        @patch.object(Foo, 'g', 1)
+        @patch.object(Foo, 'f', 1)
+        @patch.object(Foo, 'foo', new_callable=crasher)
+        def thing3():
+            pass
+
+        for func in thing1, thing2, thing3:
+            self.assertRaises(NameError, func)
+            self.assertEqual(Foo.f, original_f)
+            self.assertEqual(Foo.g, original_g)
+            self.assertEqual(Foo.foo, original_foo)
+
+
+    def test_patch_multiple_failure(self):
+        original_f = Foo.f
+        original_g = Foo.g
+
+        patcher = patch.object(Foo, 'f', 1)
+        patcher.attribute_name = 'f'
+
+        good = patch.object(Foo, 'g', 1)
+        good.attribute_name = 'g'
+
+        bad = patch.object(Foo, 'missing', 1)
+        bad.attribute_name = 'missing'
+
+        for additionals in [good, bad], [bad, good]:
+            patcher.additional_patchers = additionals
+
+            @patcher
+            def func():
+                pass
+
+            self.assertRaises(AttributeError, func)
+            self.assertEqual(Foo.f, original_f)
+            self.assertEqual(Foo.g, original_g)
+
+
+    def test_patch_multiple_new_callable_failure(self):
+        original_f = Foo.f
+        original_g = Foo.g
+        original_foo = Foo.foo
+
+        def crasher():
+            raise NameError('crasher')
+
+        patcher = patch.object(Foo, 'f', 1)
+        patcher.attribute_name = 'f'
+
+        good = patch.object(Foo, 'g', 1)
+        good.attribute_name = 'g'
+
+        bad = patch.object(Foo, 'foo', new_callable=crasher)
+        bad.attribute_name = 'foo'
+
+        for additionals in [good, bad], [bad, good]:
+            patcher.additional_patchers = additionals
+
+            @patcher
+            def func():
+                pass
+
+            self.assertRaises(NameError, func)
+            self.assertEqual(Foo.f, original_f)
+            self.assertEqual(Foo.g, original_g)
+            self.assertEqual(Foo.foo, original_foo)
+
+
+    def test_patch_multiple_string_subclasses(self):
+        for base in (str, unicode):
+            Foo = type('Foo', (base,), {'fish': 'tasty'})
+            foo = Foo()
+            @patch.multiple(foo, fish='nearly gone')
+            def test():
+                self.assertEqual(foo.fish, 'nearly gone')
+
+            test()
+            self.assertEqual(foo.fish, 'tasty')
+
+
+    @patch('mock.patch.TEST_PREFIX', 'foo')
+    def test_patch_test_prefix(self):
+        class Foo(object):
+            thing = 'original'
+
+            def foo_one(self):
+                return self.thing
+            def foo_two(self):
+                return self.thing
+            def test_one(self):
+                return self.thing
+            def test_two(self):
+                return self.thing
+
+        Foo = patch.object(Foo, 'thing', 'changed')(Foo)
+
+        foo = Foo()
+        self.assertEqual(foo.foo_one(), 'changed')
+        self.assertEqual(foo.foo_two(), 'changed')
+        self.assertEqual(foo.test_one(), 'original')
+        self.assertEqual(foo.test_two(), 'original')
+
+
+    @patch('mock.patch.TEST_PREFIX', 'bar')
+    def test_patch_dict_test_prefix(self):
+        class Foo(object):
+            def bar_one(self):
+                return dict(the_dict)
+            def bar_two(self):
+                return dict(the_dict)
+            def test_one(self):
+                return dict(the_dict)
+            def test_two(self):
+                return dict(the_dict)
+
+        the_dict = {'key': 'original'}
+        Foo = patch.dict(the_dict, key='changed')(Foo)
+
+        foo =Foo()
+        self.assertEqual(foo.bar_one(), {'key': 'changed'})
+        self.assertEqual(foo.bar_two(), {'key': 'changed'})
+        self.assertEqual(foo.test_one(), {'key': 'original'})
+        self.assertEqual(foo.test_two(), {'key': 'original'})
+
+
+    def test_patch_with_spec_mock_repr(self):
+        for arg in ('spec', 'autospec', 'spec_set'):
+            p = patch('%s.SomeClass' % __name__, **{arg: True})
+            m = p.start()
+            try:
+                self.assertIn(" name='SomeClass'", repr(m))
+                self.assertIn(" name='SomeClass.class_attribute'",
+                              repr(m.class_attribute))
+                self.assertIn(" name='SomeClass()'", repr(m()))
+                self.assertIn(" name='SomeClass().class_attribute'",
+                              repr(m().class_attribute))
+            finally:
+                p.stop()
+
+
+    def test_patch_nested_autospec_repr(self):
+        p = patch('tests.support', autospec=True)
+        m = p.start()
+        try:
+            self.assertIn(" name='support.SomeClass.wibble()'",
+                          repr(m.SomeClass.wibble()))
+            self.assertIn(" name='support.SomeClass().wibble()'",
+                          repr(m.SomeClass().wibble()))
+        finally:
+            p.stop()
+
+
+    def test_mock_calls_with_patch(self):
+        for arg in ('spec', 'autospec', 'spec_set'):
+            p = patch('%s.SomeClass' % __name__, **{arg: True})
+            m = p.start()
+            try:
+                m.wibble()
+
+                kalls = [call.wibble()]
+                self.assertEqual(m.mock_calls, kalls)
+                self.assertEqual(m.method_calls, kalls)
+                self.assertEqual(m.wibble.mock_calls, [call()])
+
+                result = m()
+                kalls.append(call())
+                self.assertEqual(m.mock_calls, kalls)
+
+                result.wibble()
+                kalls.append(call().wibble())
+                self.assertEqual(m.mock_calls, kalls)
+
+                self.assertEqual(result.mock_calls, [call.wibble()])
+                self.assertEqual(result.wibble.mock_calls, [call()])
+                self.assertEqual(result.method_calls, [call.wibble()])
+            finally:
+                p.stop()
+
+
+    def test_patch_imports_lazily(self):
+        sys.modules.pop('squizz', None)
+
+        p1 = patch('squizz.squozz')
+        self.assertRaises(ImportError, p1.start)
+
+        squizz = Mock()
+        squizz.squozz = 6
+        sys.modules['squizz'] = squizz
+        p1 = patch('squizz.squozz')
+        squizz.squozz = 3
+        p1.start()
+        p1.stop()
+        self.assertEqual(squizz.squozz, 3)
+
+
+    def test_patch_propogrates_exc_on_exit(self):
+        class holder:
+            exc_info = None, None, None
+
+        class custom_patch(_patch):
+            def __exit__(self, etype=None, val=None, tb=None):
+                _patch.__exit__(self, etype, val, tb)
+                holder.exc_info = etype, val, tb
+            stop = __exit__
+
+        def with_custom_patch(target):
+            getter, attribute = _get_target(target)
+            return custom_patch(
+                getter, attribute, DEFAULT, None, False, None,
+                None, None, {}
+            )
+
+        @with_custom_patch('squizz.squozz')
+        def test(mock):
+            raise RuntimeError
+
+        self.assertRaises(RuntimeError, test)
+        self.assertIs(holder.exc_info[0], RuntimeError)
+        self.assertIsNotNone(holder.exc_info[1],
+                            'exception value not propgated')
+        self.assertIsNotNone(holder.exc_info[2],
+                            'exception traceback not propgated')
+
+
+    def test_create_and_specs(self):
+        for kwarg in ('spec', 'spec_set', 'autospec'):
+            p = patch('%s.doesnotexist' % __name__, create=True,
+                      **{kwarg: True})
+            self.assertRaises(TypeError, p.start)
+            self.assertRaises(NameError, lambda: doesnotexist)
+
+            # check that spec with create is innocuous if the original exists
+            p = patch(MODNAME, create=True, **{kwarg: True})
+            p.start()
+            p.stop()
+
+
+    def test_multiple_specs(self):
+        original = PTModule
+        for kwarg in ('spec', 'spec_set'):
+            p = patch(MODNAME, autospec=0, **{kwarg: 0})
+            self.assertRaises(TypeError, p.start)
+            self.assertIs(PTModule, original)
+
+        for kwarg in ('spec', 'autospec'):
+            p = patch(MODNAME, spec_set=0, **{kwarg: 0})
+            self.assertRaises(TypeError, p.start)
+            self.assertIs(PTModule, original)
+
+        for kwarg in ('spec_set', 'autospec'):
+            p = patch(MODNAME, spec=0, **{kwarg: 0})
+            self.assertRaises(TypeError, p.start)
+            self.assertIs(PTModule, original)
+
+
+    def test_specs_false_instead_of_none(self):
+        p = patch(MODNAME, spec=False, spec_set=False, autospec=False)
+        mock = p.start()
+        try:
+            # no spec should have been set, so attribute access should not fail
+            mock.does_not_exist
+            mock.does_not_exist = 3
+        finally:
+            p.stop()
+
+
+    def test_falsey_spec(self):
+        for kwarg in ('spec', 'autospec', 'spec_set'):
+            p = patch(MODNAME, **{kwarg: 0})
+            m = p.start()
+            try:
+                self.assertRaises(AttributeError, getattr, m, 'doesnotexit')
+            finally:
+                p.stop()
+
+
+    def test_spec_set_true(self):
+        for kwarg in ('spec', 'autospec'):
+            p = patch(MODNAME, spec_set=True, **{kwarg: True})
+            m = p.start()
+            try:
+                self.assertRaises(AttributeError, setattr, m,
+                                  'doesnotexist', 'something')
+                self.assertRaises(AttributeError, getattr, m, 'doesnotexist')
+            finally:
+                p.stop()
+
+
+    def test_callable_spec_as_list(self):
+        spec = ('__call__',)
+        p = patch(MODNAME, spec=spec)
+        m = p.start()
+        try:
+            self.assertTrue(callable(m))
+        finally:
+            p.stop()
+
+
+    def test_not_callable_spec_as_list(self):
+        spec = ('foo', 'bar')
+        p = patch(MODNAME, spec=spec)
+        m = p.start()
+        try:
+            self.assertFalse(callable(m))
+        finally:
+            p.stop()
+
+
+    def test_patch_stopall(self):
+        unlink = os.unlink
+        chdir = os.chdir
+        path = os.path
+        patch('os.unlink', something).start()
+        patch('os.chdir', something_else).start()
+
+        @patch('os.path')
+        def patched(mock_path):
+            patch.stopall()
+            self.assertIs(os.path, mock_path)
+            self.assertIs(os.unlink, unlink)
+            self.assertIs(os.chdir, chdir)
+
+        patched()
+        self.assertIs(os.path, path)
+
+
+    def test_wrapped_patch(self):
+        decorated = patch('sys.modules')(function)
+        self.assertIs(decorated.__wrapped__, function)
+
+
+    def test_wrapped_several_times_patch(self):
+        decorated = patch('sys.modules')(function)
+        decorated = patch('sys.modules')(decorated)
+        self.assertIs(decorated.__wrapped__, function)
+
+
+    def test_wrapped_patch_object(self):
+        decorated = patch.object(sys, 'modules')(function)
+        self.assertIs(decorated.__wrapped__, function)
+
+
+    def test_wrapped_patch_dict(self):
+        decorated = patch.dict('sys.modules')(function)
+        self.assertIs(decorated.__wrapped__, function)
+
+
+    def test_wrapped_patch_multiple(self):
+        decorated = patch.multiple('sys', modules={})(function)
+        self.assertIs(decorated.__wrapped__, function)
+
+
+if __name__ == '__main__':
+    unittest2.main()

Added: incubator/ambari/branches/branch-1.2/ambari-common/src/test/python/mock/tests/testsentinel.py
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.2/ambari-common/src/test/python/mock/tests/testsentinel.py?rev=1442010&view=auto
==============================================================================
--- incubator/ambari/branches/branch-1.2/ambari-common/src/test/python/mock/tests/testsentinel.py (added)
+++ incubator/ambari/branches/branch-1.2/ambari-common/src/test/python/mock/tests/testsentinel.py Mon Feb  4 02:23:55 2013
@@ -0,0 +1,33 @@
+# Copyright (C) 2007-2012 Michael Foord & the mock team
+# E-mail: fuzzyman AT voidspace DOT org DOT uk
+# http://www.voidspace.org.uk/python/mock/
+
+from tests.support import unittest2
+
+from mock import sentinel, DEFAULT
+
+
+class SentinelTest(unittest2.TestCase):
+
+    def testSentinels(self):
+        self.assertEqual(sentinel.whatever, sentinel.whatever,
+                         'sentinel not stored')
+        self.assertNotEqual(sentinel.whatever, sentinel.whateverelse,
+                            'sentinel should be unique')
+
+
+    def testSentinelName(self):
+        self.assertEqual(str(sentinel.whatever), 'sentinel.whatever',
+                         'sentinel name incorrect')
+
+
+    def testDEFAULT(self):
+        self.assertTrue(DEFAULT is sentinel.DEFAULT)
+
+    def testBases(self):
+        # If this doesn't raise an AttributeError then help(mock) is broken
+        self.assertRaises(AttributeError, lambda: sentinel.__bases__)
+
+
+if __name__ == '__main__':
+    unittest2.main()

Added: incubator/ambari/branches/branch-1.2/ambari-common/src/test/python/mock/tests/testwith.py
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.2/ambari-common/src/test/python/mock/tests/testwith.py?rev=1442010&view=auto
==============================================================================
--- incubator/ambari/branches/branch-1.2/ambari-common/src/test/python/mock/tests/testwith.py (added)
+++ incubator/ambari/branches/branch-1.2/ambari-common/src/test/python/mock/tests/testwith.py Mon Feb  4 02:23:55 2013
@@ -0,0 +1,16 @@
+import sys
+
+if sys.version_info[:2] >= (2, 5):
+    from tests._testwith import *
+else:
+    from tests.support import unittest2
+
+    class TestWith(unittest2.TestCase):
+
+        @unittest2.skip('tests using with statement skipped on Python 2.4')
+        def testWith(self):
+            pass
+
+
+if __name__ == '__main__':
+    unittest2.main()

Added: incubator/ambari/branches/branch-1.2/ambari-common/src/test/python/mock/tox.ini
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.2/ambari-common/src/test/python/mock/tox.ini?rev=1442010&view=auto
==============================================================================
--- incubator/ambari/branches/branch-1.2/ambari-common/src/test/python/mock/tox.ini (added)
+++ incubator/ambari/branches/branch-1.2/ambari-common/src/test/python/mock/tox.ini Mon Feb  4 02:23:55 2013
@@ -0,0 +1,40 @@
+[tox]
+envlist = py25,py26,py27,py31,pypy,py32,py33,jython
+
+[testenv]
+deps=unittest2
+commands={envbindir}/unit2 discover []
+
+[testenv:py26]
+commands=
+    {envbindir}/unit2 discover []
+    {envbindir}/sphinx-build -E -b doctest docs html
+    {envbindir}/sphinx-build -E docs html
+deps =
+    unittest2
+    sphinx
+
+[testenv:py27]
+commands=
+    {envbindir}/unit2 discover []
+    {envbindir}/sphinx-build -E -b doctest docs html
+deps =
+    unittest2
+    sphinx
+
+[testenv:py31]
+deps =
+    unittest2py3k
+
+[testenv:py32]
+commands=
+    {envbindir}/python -m unittest discover []
+deps =
+
+[testenv:py33]
+commands=
+    {envbindir}/python -m unittest discover []
+deps =
+
+# note for jython. Execute in tests directory:
+# rm `find . -name '*$py.class'`
\ No newline at end of file

Added: incubator/ambari/branches/branch-1.2/ambari-common/src/test/python/mock/unittest.cfg
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.2/ambari-common/src/test/python/mock/unittest.cfg?rev=1442010&view=auto
==============================================================================
--- incubator/ambari/branches/branch-1.2/ambari-common/src/test/python/mock/unittest.cfg (added)
+++ incubator/ambari/branches/branch-1.2/ambari-common/src/test/python/mock/unittest.cfg Mon Feb  4 02:23:55 2013
@@ -0,0 +1,95 @@
+
+[unittest]
+plugins = 
+    unittest2.plugins.debugger
+    unittest2.plugins.checker
+    unittest2.plugins.doctestloader
+    unittest2.plugins.matchregexp
+    unittest2.plugins.moduleloading
+    unittest2.plugins.testcoverage
+    unittest2.plugins.growl
+    unittest2.plugins.filtertests
+    unittest2.plugins.junitxml
+    unittest2.plugins.timed
+    unittest2.plugins.counttests
+    unittest2.plugins.logchannels
+
+excluded-plugins =
+
+# 0, 1 or 2 (default is 1)
+# quiet, normal or verbose
+# can be overriden at command line
+verbosity = normal
+
+# true or false
+# even if false can be switched on at command line
+catch =
+buffer =
+failfast =
+
+
+[matchregexp]
+always-on = False
+full-path = True
+
+[debugger]
+always-on = False
+errors-only = True
+
+[coverage]
+always-on = False
+config =
+report-html = False
+# only used if report-html is false
+annotate = False
+# defaults to './htmlcov/'
+html-directory =
+# if unset will output to console
+text-file =
+branch = False
+timid = False
+cover-pylib = False
+exclude-lines = 
+    # Have to re-enable the standard pragma
+    pragma: no cover
+
+    # Don't complain about missing debug-only code:
+    def __repr__
+    if self\.debug
+
+    # Don't complain if tests don't hit defensive assertion code:
+    raise AssertionError
+    raise NotImplementedError
+
+    # Don't complain if non-runnable code isn't run:
+    if 0:
+    if __name__ == .__main__.
+    
+ignore-errors = False
+modules =
+
+[growl]
+always-on = False
+
+[doctest]
+always-on = False
+
+[module-loading]
+always-on = False
+
+[checker]
+always-on = False
+pep8 = False
+pyflakes = True
+
+[junit-xml]
+always-on = False
+path = junit.xml
+
+[timed]
+always-on = True
+threshold = 0.01
+
+[count]
+always-on = True
+enhanced = False

Modified: incubator/ambari/branches/branch-1.2/ambari-project/pom.xml
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.2/ambari-project/pom.xml?rev=1442010&r1=1442009&r2=1442010&view=diff
==============================================================================
--- incubator/ambari/branches/branch-1.2/ambari-project/pom.xml (original)
+++ incubator/ambari/branches/branch-1.2/ambari-project/pom.xml Mon Feb  4 02:23:55 2013
@@ -17,11 +17,11 @@
   <parent>
     <groupId>org.apache.ambari</groupId>
     <artifactId>ambari</artifactId>
-    <version>1.2.0-SNAPSHOT</version>
+    <version>1.2.1-SNAPSHOT</version>
   </parent>
   <groupId>org.apache.ambari</groupId>
   <artifactId>ambari-project</artifactId>
-  <version>1.2.0-SNAPSHOT</version>
+  <version>1.2.1-SNAPSHOT</version>
   <description>Apache Ambari Project POM</description>
   <name>Apache Ambari Project POM</name>
   <packaging>pom</packaging>

Added: incubator/ambari/branches/branch-1.2/ambari-server/pass.txt
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.2/ambari-server/pass.txt?rev=1442010&view=auto
==============================================================================
--- incubator/ambari/branches/branch-1.2/ambari-server/pass.txt (added)
+++ incubator/ambari/branches/branch-1.2/ambari-server/pass.txt Mon Feb  4 02:23:55 2013
@@ -0,0 +1 @@
+k0n9LEBvrNOBzCw4drmUBSnCykzL0ZVzt5cZyLXvJtlsQZpUNq
\ No newline at end of file

Modified: incubator/ambari/branches/branch-1.2/ambari-server/pom.xml
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.2/ambari-server/pom.xml?rev=1442010&r1=1442009&r2=1442010&view=diff
==============================================================================
--- incubator/ambari/branches/branch-1.2/ambari-server/pom.xml (original)
+++ incubator/ambari/branches/branch-1.2/ambari-server/pom.xml Mon Feb  4 02:23:55 2013
@@ -16,7 +16,7 @@
   <parent>
     <groupId>org.apache.ambari</groupId>
     <artifactId>ambari-project</artifactId>
-    <version>1.2.0-SNAPSHOT</version>
+    <version>1.2.1-SNAPSHOT</version>
     <relativePath>../ambari-project</relativePath>
   </parent>
   <modelVersion>4.0.0</modelVersion>
@@ -24,7 +24,7 @@
   <artifactId>ambari-server</artifactId>
   <packaging>jar</packaging>
   <name>Ambari Server</name>
-  <version>1.2.0-SNAPSHOT</version>
+  <version>1.2.1-SNAPSHOT</version>
   <description>Ambari Server</description>
   <properties>
     <python.ver>python &gt;= 2.6</python.ver>
@@ -64,6 +64,9 @@
 
             <!--gitignore content-->
             <exclude>src/main/resources/db/newcerts/**</exclude>
+
+            <!--test samples-->
+            <exclude>src/test/resources/TestAmbaryServer.samples/**</exclude>
           </excludes>
         </configuration>
       </plugin>
@@ -96,6 +99,9 @@
             <require>openssl</require>
             <require>${python.ver}</require>
           </requires>
+          <preremoveScriptlet>
+            <script>mv /etc/ambari-server/conf /etc/ambari-server/conf.save</script>
+          </preremoveScriptlet>
           <mappings>
             <mapping>
               <directory>/usr/lib/ambari-server</directory>
@@ -227,6 +233,23 @@
               </sources>
             </mapping>
             <mapping>
+              <directory>/var/lib/ambari-server/resources/upgrade</directory>
+              <filemode>755</filemode>
+              <username>root</username>
+              <groupname>root</groupname>
+            </mapping>
+            <mapping>
+              <directory>/var/lib/ambari-server/resources/upgrade/ddl</directory>
+              <filemode>755</filemode>
+              <username>root</username>
+              <groupname>root</groupname>
+              <sources>
+                <source>
+                  <location>src/main/resources/upgrade/ddl/Ambari-DDL-Postgres-UPGRADE-1.2.1.sql</location>
+                </source>
+              </sources>
+            </mapping>
+            <mapping>
               <directory>/var/lib/ambari-server/resources/stacks</directory>
               <filemode>755</filemode>
               <username>root</username>
@@ -276,6 +299,31 @@
           </execution>
         </executions>
       </plugin>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>exec-maven-plugin</artifactId>
+        <version>1.2</version>
+        <executions>
+          <execution>
+            <configuration>
+              <executable>python2.6</executable>
+              <workingDirectory>src/test/python</workingDirectory>
+              <arguments>
+                <argument>unitTests.py</argument>
+              </arguments>
+              <environmentVariables>
+                <PYTHONPATH>${project.basedir}/../ambari-common/src/test/python:${project.basedir}/src/main/python:${project.basedir}/src/main/python/ambari-server-state:${project.basedir}/src/test/python:$PYTHONPATH</PYTHONPATH>
+              </environmentVariables>
+              <skip>${skipTests}</skip>
+            </configuration>
+            <id>python-test</id>
+            <phase>test</phase>
+            <goals>
+              <goal>exec</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
     </plugins>
   </build>
   <profiles>
@@ -500,7 +548,7 @@
     <dependency>
       <groupId>postgresql</groupId>
       <artifactId>postgresql</artifactId>
-      <version>8.3-603.jdbc4</version>
+      <version>9.1-901.jdbc4</version>
     </dependency>
   </dependencies>
   <!--<reporting>

Modified: incubator/ambari/branches/branch-1.2/ambari-server/sbin/ambari-server
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.2/ambari-server/sbin/ambari-server?rev=1442010&r1=1442009&r2=1442010&view=diff
==============================================================================
--- incubator/ambari/branches/branch-1.2/ambari-server/sbin/ambari-server (original)
+++ incubator/ambari/branches/branch-1.2/ambari-server/sbin/ambari-server Mon Feb  4 02:23:55 2013
@@ -73,6 +73,10 @@ case "$1" in
         $0 stop
         $0 start
         ;;
+  upgrade)
+        echo -e "Upgrading ambari-server"
+        $PYTHON /usr/sbin/ambari-server.py $@
+        ;;
   setup)
         echo -e "Run postgresql initdb"
         initdb_res=`/sbin/service postgresql initdb`
@@ -85,7 +89,7 @@ case "$1" in
         $PYTHON /usr/sbin/ambari-server.py $@
         ;;
   *)
-        echo "Usage: /usr/sbin/ambari-server {start|stop|restart|setup} [options]"
+        echo "Usage: /usr/sbin/ambari-server {start|stop|restart|setup|upgrade} [options]"
         exit 1
 esac
 

Modified: incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/eventdb/db/PostgresConnector.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/eventdb/db/PostgresConnector.java?rev=1442010&r1=1442009&r2=1442010&view=diff
==============================================================================
--- incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/eventdb/db/PostgresConnector.java (original)
+++ incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/eventdb/db/PostgresConnector.java Mon Feb  4 02:23:55 2013
@@ -245,6 +245,13 @@ public class PostgresConnector implement
     DataTable table = new DataTable();
     table.setiTotalRecords(total);
     table.setiTotalDisplayRecords(summary.getNumRows());
+    if (workflows.isEmpty()) {
+      table.setStartIndex(-1);
+      table.setEndIndex(-1);
+    } else {
+      table.setStartIndex(offset);
+      table.setEndIndex(offset + workflows.size() - 1);
+    }
     table.setAaData(workflows);
     table.setsEcho(echo);
     table.setSummary(summary);
@@ -440,7 +447,7 @@ public class PostgresConnector implement
     return field.toString() + " >= " + s;
   }
   
-  private static final String WHERE = " where";
+  private static final String WHERE = " where ";
   
   private static String buildSearchClause(String searchTerm, String searchWorkflowId, String searchWorkflowName, String searchWorkflowType,
       String searchUserName, int minJobs, int maxJobs, long minInputBytes, long maxInputBytes, long minOutputBytes, long maxOutputBytes, long minDuration,
@@ -448,7 +455,7 @@ public class PostgresConnector implement
     StringBuilder sb = new StringBuilder();
     sb.append(WHERE);
     if (searchTerm != null && searchTerm.length() > 0) {
-      sb.append(" (");
+      sb.append("(");
       sb.append(like(WorkflowFields.WORKFLOWID, searchTerm));
       sb.append(" or ");
       sb.append(like(WorkflowFields.WORKFLOWNAME, searchTerm));

Modified: incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/eventdb/model/DataTable.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/eventdb/model/DataTable.java?rev=1442010&r1=1442009&r2=1442010&view=diff
==============================================================================
--- incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/eventdb/model/DataTable.java (original)
+++ incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/eventdb/model/DataTable.java Mon Feb  4 02:23:55 2013
@@ -33,6 +33,8 @@ public class DataTable {
   int sEcho;
   int iTotalRecords;
   int iTotalDisplayRecords;
+  int startIndex;
+  int endIndex;
   List<WorkflowDBEntry> aaData;
   Summary summary;
   
@@ -206,6 +208,22 @@ public class DataTable {
     this.iTotalDisplayRecords = iTotalDisplayRecords;
   }
   
+  public int getStartIndex() {
+    return startIndex;
+  }
+  
+  public void setStartIndex(int startIndex) {
+    this.startIndex = startIndex;
+  }
+  
+  public int getEndIndex() {
+    return endIndex;
+  }
+  
+  public void setEndIndex(int endIndex) {
+    this.endIndex = endIndex;
+  }
+  
   public List<WorkflowDBEntry> getAaData() {
     return aaData;
   }

Modified: incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionManager.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionManager.java?rev=1442010&r1=1442009&r2=1442010&view=diff
==============================================================================
--- incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionManager.java (original)
+++ incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionManager.java Mon Feb  4 02:23:55 2013
@@ -24,6 +24,7 @@ import java.util.concurrent.atomic.Atomi
 
 import org.apache.ambari.server.agent.ActionQueue;
 import org.apache.ambari.server.agent.CommandReport;
+import org.apache.ambari.server.controller.HostsMap;
 import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.utils.StageUtils;
 import org.slf4j.Logger;
@@ -42,17 +43,19 @@ public class ActionManager {
   private final ActionScheduler scheduler;
   private final ActionDBAccessor db;
   private final ActionQueue actionQueue;
+  private final HostsMap hostsMap;
   private static Logger LOG = LoggerFactory.getLogger(ActionManager.class);
   private final AtomicLong requestCounter;
 
   @Inject
   public ActionManager(@Named("schedulerSleeptime") long schedulerSleepTime,
       @Named("actionTimeout") long actionTimeout,
-      ActionQueue aq, Clusters fsm, ActionDBAccessor db) {
+      ActionQueue aq, Clusters fsm, ActionDBAccessor db, HostsMap hostsMap) {
     this.actionQueue = aq;
     this.db = db;
+    this.hostsMap = hostsMap;
     scheduler = new ActionScheduler(schedulerSleepTime, actionTimeout, db,
-        actionQueue, fsm, 2);
+        actionQueue, fsm, 2, hostsMap);
     requestCounter = new AtomicLong(
         db.getLastPersistedRequestIdWhenInitialized());
   }

Modified: incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionScheduler.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionScheduler.java?rev=1442010&r1=1442009&r2=1442010&view=diff
==============================================================================
--- incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionScheduler.java (original)
+++ incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionScheduler.java Mon Feb  4 02:23:55 2013
@@ -28,6 +28,7 @@ import org.apache.ambari.server.Role;
 import org.apache.ambari.server.ServiceComponentNotFoundException;
 import org.apache.ambari.server.agent.ActionQueue;
 import org.apache.ambari.server.agent.ExecutionCommand;
+import org.apache.ambari.server.controller.HostsMap;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.Service;
@@ -54,11 +55,13 @@ class ActionScheduler implements Runnabl
   private final ActionQueue actionQueue;
   private final Clusters fsmObject;
   private boolean taskTimeoutAdjustment = true;
+  private final HostsMap hostsMap;
 
   public ActionScheduler(long sleepTimeMilliSec, long actionTimeoutMilliSec,
       ActionDBAccessor db, ActionQueue actionQueue, Clusters fsmObject,
-      int maxAttempts) {
+      int maxAttempts, HostsMap hostsMap) {
     this.sleepTime = sleepTimeMilliSec;
+    this.hostsMap = hostsMap;
     this.actionTimeout = actionTimeoutMilliSec;
     this.db = db;
     this.actionQueue = actionQueue;
@@ -283,6 +286,8 @@ class ActionScheduler implements Runnabl
     s.setLastAttemptTime(hostname, roleStr, now);
     s.incrementAttemptCount(hostname, roleStr);
     LOG.info("Scheduling command: "+cmd.toString()+" for host: "+hostname);
+    /** change the hostname in the command for the host itself **/
+    cmd.setHostname(hostsMap.getHostMap(hostname));
     actionQueue.enqueue(hostname, cmd);
     db.hostRoleScheduled(s, hostname, roleStr);
   }

Added: incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/agent/AgentEnv.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/agent/AgentEnv.java?rev=1442010&view=auto
==============================================================================
--- incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/agent/AgentEnv.java (added)
+++ incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/agent/AgentEnv.java Mon Feb  4 02:23:55 2013
@@ -0,0 +1,242 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.agent;
+
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;
+
+/**
+ * Agent environment data.
+ */
+public class AgentEnv {
+
+  /**
+   * Various directories, configurable in <code>ambari-agent.ini</code>
+   */
+  private Directory[] paths = new Directory[0];
+
+  /**
+   * Java processes running on the system.  Default empty array.
+   */
+  private JavaProc[] javaProcs = new JavaProc[0];
+  
+  /**
+   * Various RPM package versions.
+   */
+  private Rpm[] rpms = new Rpm[0];
+  
+  /**
+   * Number of pid files found in <code>/var/run/hadoop</code>
+   */
+  private int varRunHadoopPidCount = 0;
+  
+  /**
+   * Number of log files found in <code>/var/log/hadoop</code>
+   */
+  private int varLogHadoopLogCount = 0;
+
+  /**
+   * Directories that match name <code>/etc/alternatives/*conf</code>
+   */
+  private Alternative[] etcAlternativesConf = new Alternative[0];
+
+  /**
+   * Output for repo listing.  Command to do this varies, but for RHEL it is
+   * <code>yum -C repolist</code>
+   */
+  private String repoInfo;
+  
+
+  public Directory[] getPaths() {
+      return paths;
+  }
+  
+  public void setPaths(Directory[] dirs) {
+    paths = dirs;
+  }
+  
+  public void setVarRunHadoopPidCount(int count) {
+    varRunHadoopPidCount = count;
+  }
+  
+  public int getVarRunHadoopPidCount() {
+    return varRunHadoopPidCount;
+  }
+  
+  public void setVarLogHadoopLogCount(int count) {
+    varLogHadoopLogCount = count;
+  }
+  
+  public int getVarLogHadoopLogCount() {
+    return varLogHadoopLogCount;
+  }
+  
+  public void setJavaProcs(JavaProc[] procs) {
+    javaProcs = procs;
+  }
+  
+  public JavaProc[] getJavaProcs() {
+    return javaProcs;
+  }
+  
+  public void setRpms(Rpm[] rpm) {
+    rpms = rpm;
+  }
+  
+  public Rpm[] getRpms() {
+    return rpms;
+  }
+  
+  public void setEtcAlternativesConf(Alternative[] dirs) {
+    etcAlternativesConf = dirs;
+  }
+  
+  public Alternative[] getEtcAlternativesConf() {
+    return etcAlternativesConf;
+  }
+  
+  public void setRepoInfo(String info) {
+    repoInfo = info;
+  }
+  
+  public String getRepoInfo() {
+    return repoInfo;
+  }
+  
+  /**
+   * Represents information about rpm-installed packages
+   */
+  public static class Rpm {
+    private String rpmName;
+    private boolean rpmInstalled = false;
+    private String rpmVersion;
+    
+    public void setName(String name) {
+      rpmName = name;
+    }
+    
+    public String getName() {
+      return rpmName;
+    }
+    
+    public void setInstalled(boolean installed) {
+      rpmInstalled = installed;
+    }
+    
+    public boolean isInstalled() {
+      return rpmInstalled;
+    }
+    
+    public void setVersion(String version) {
+      rpmVersion = version;
+    }
+    
+    @JsonSerialize(include=Inclusion.NON_NULL)
+    public String getVersion() {
+      return rpmVersion;
+    }
+  }
+  
+  /**
+   * Represents information about a directory of interest.
+   */
+  public static class Directory {
+    private String dirName;
+    private String dirType;
+    
+    public void setName(String name) {
+      dirName = name;
+    }
+    
+    public String getName() {
+      return dirName;
+    }
+    
+    public void setType(String type) {
+      dirType = type;
+    }
+    
+    public String getType() {
+      return dirType;
+    }
+  }
+  
+  /**
+   * Represents information about running java processes.
+   */
+  public static class JavaProc {
+    private String user;
+    private int pid = 0;
+    private boolean is_hadoop = false;
+    private String command;
+    
+    public void setUser(String user) {
+      this.user = user;
+    }
+    
+    public String getUser() {
+      return user;
+    }
+    
+    public void setPid(int pid) {
+      this.pid = pid;
+    }
+    
+    public int getPid() {
+      return pid;
+    }
+    
+    public void setHadoop(boolean hadoop) {
+      is_hadoop = hadoop;
+    }
+    
+    public boolean isHadoop() {
+      return is_hadoop;
+    }
+    
+    public void setCommand(String cmd) {
+      command = cmd;
+    }
+    
+    public String getCommand() {
+      return command;
+    }
+  }
+  
+  public static class Alternative {
+    private String altName;
+    private String altTarget;
+    
+    public void setName(String name) {
+      altName = name;
+    }
+    
+    public String getName() {
+      return altName;
+    }
+    
+    public void setTarget(String target) {
+      altTarget = target;
+    }
+    
+    public String getTarget() {
+      return altTarget;
+    }
+  }
+  
+}

Modified: incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeat.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeat.java?rev=1442010&r1=1442009&r2=1442010&view=diff
==============================================================================
--- incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeat.java (original)
+++ incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeat.java Mon Feb  4 02:23:55 2013
@@ -37,6 +37,7 @@ public class HeartBeat {
   List<CommandReport> reports = new ArrayList<CommandReport>();
   List<ComponentStatus> componentStatus = new ArrayList<ComponentStatus>();
   HostStatus nodeStatus;
+  private AgentEnv agentEnv = null;
 
   public long getResponseId() {
     return responseId;
@@ -79,6 +80,14 @@ public class HeartBeat {
   public void setNodeStatus(HostStatus nodeStatus) {
     this.nodeStatus = nodeStatus;
   }
+  
+  public AgentEnv getAgentEnv() {
+    return agentEnv;
+  }
+  
+  public void setAgentEnv(AgentEnv env) {
+    agentEnv = env;
+  }
 
   @JsonProperty("componentStatus")
   public List<ComponentStatus> getComponentStatus() {

Modified: incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java?rev=1442010&r1=1442009&r2=1442010&view=diff
==============================================================================
--- incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java (original)
+++ incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java Mon Feb  4 02:23:55 2013
@@ -151,9 +151,9 @@ public class HeartBeatHandler {
     }
 
     try {
-      if (heartbeat.getNodeStatus().getStatus()
-          .equals(HostStatus.Status.HEALTHY)) {
-        hostObject.handleEvent(new HostHealthyHeartbeatEvent(hostname, now));
+      if (heartbeat.getNodeStatus().getStatus().equals(HostStatus.Status.HEALTHY)) {
+        hostObject.handleEvent(new HostHealthyHeartbeatEvent(hostname, now,
+            heartbeat.getAgentEnv()));
       } else {
         hostObject.handleEvent(new HostUnhealthyHeartbeatEvent(hostname, now,
             null));
@@ -224,6 +224,12 @@ public class HeartBeatHandler {
                   || prevState.equals(State.START_FAILED)
                   || prevState.equals(State.STARTED)
                   || prevState.equals(State.STOP_FAILED)) {
+                if (prevState == State.START_FAILED
+                        && liveState == State.INSTALLED) {
+                  LOG.info("Ignoring INSTALLED state update for " +
+                          "START_FAILED component");
+                  continue;
+                }
                 scHost.setState(liveState);
                 if (!prevState.equals(liveState)) {
                   LOG.info("State of service component " + componentName
@@ -349,7 +355,7 @@ public class HeartBeatHandler {
 
     hostObject.handleEvent(new HostRegistrationRequestEvent(hostname,
         null != register.getPublicHostname() ? register.getPublicHostname() : hostname,
-        new AgentVersion("v1"), now, register.getHardwareProfile()));
+        new AgentVersion("v1"), now, register.getHardwareProfile(), register.getAgentEnv()));
     RegistrationResponse response = new RegistrationResponse();
     if (cmds.isEmpty()) {
       //No status commands needed let the fsm know that status step is done

Modified: incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatMonitor.java
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatMonitor.java?rev=1442010&r1=1442009&r2=1442010&view=diff
==============================================================================
--- incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatMonitor.java (original)
+++ incubator/ambari/branches/branch-1.2/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatMonitor.java Mon Feb  4 02:23:55 2013
@@ -19,13 +19,19 @@ package org.apache.ambari.server.agent;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
 
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.actionmanager.ActionManager;
-import org.apache.ambari.server.state.*;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.Config;
+import org.apache.ambari.server.state.Host;
+import org.apache.ambari.server.state.HostState;
+import org.apache.ambari.server.state.ServiceComponentHost;
 import org.apache.ambari.server.state.fsm.InvalidStateTransitionException;
 import org.apache.ambari.server.state.host.HostHeartbeatLostEvent;
-import org.apache.ambari.server.state.host.HostStatusUpdatesReceivedEvent;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
@@ -145,10 +151,23 @@ public class HeartbeatMonitor implements
           LOG.debug("Live status will include status of service " + serviceName +
                 " of cluster " + cl.getClusterName());
         }
+        
+        Map<String, Config> configs = sch.getDesiredConfigs();
+        
+        Map<String, Map<String, String>> configurations =
+            new TreeMap<String, Map<String, String>>();
+        
+        for (Config config : configs.values()) {
+          if (config.getType().equals("global"))
+            configurations.put(config.getType(),
+              config.getProperties());
+        }
+        
         StatusCommand statusCmd = new StatusCommand();
         statusCmd.setClusterName(cl.getClusterName());
         statusCmd.setServiceName(serviceName);
         statusCmd.setComponentName(sch.getServiceComponentName());
+        statusCmd.setConfigurations(configurations);			
         cmds.add(statusCmd);
       }
     }