diff --git a/v2/test/__init__.py b/v2/test/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/v2/test/compat.py b/v2/test/compat.py
new file mode 100644
index 00000000000..6c122f2fad6
--- /dev/null
+++ b/v2/test/compat.py
@@ -0,0 +1,51 @@
+# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
+
+import unittest
+
+#
+# Compat for python2.6
+#
+
+if sys.version_info < (2, 7):
+    try:
+        # Need unittest2 on python2.6
+        import unittest2 as unittest
+    except ImportError:
+        print('You need unittest2 installed on python2.x')
+else:
+    import unittest
+
+
+#
+# Compat for python2.7
+#
+
+# Could use the pypi mock library on py3 as well as py2.  They are the same
+try:
+    from unittest.mock import mock_open, patch
+except ImportError:
+    # Python2
+    from mock import mock_open, patch
+
+try:
+    import __builtin__
+except ImportError:
+    BUILTINS = 'builtins'
+else:
+    BUILTINS = '__builtin__'
+
diff --git a/v2/test/errors/__init__.py b/v2/test/errors/__init__.py
new file mode 100644
index 00000000000..674334b15a3
--- /dev/null
+++ b/v2/test/errors/__init__.py
@@ -0,0 +1,18 @@
+# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
+
+
diff --git a/v2/test/errors/test_errors.py b/v2/test/errors/test_errors.py
new file mode 100644
index 00000000000..ff3b562d25c
--- /dev/null
+++ b/v2/test/errors/test_errors.py
@@ -0,0 +1,48 @@
+# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
+
+from ..compat import unittest
+
+from ansible.parsing.yaml.objects import AnsibleBaseYAMLObject
+from ansible.errors import AnsibleError
+
+from .. compat import BUILTINS, mock_open, patch
+
+class TestErrors(unittest.TestCase):
+
+    def setUp(self):
+        self.message = 'this is the error message'
+
+    def tearDown(self):
+        pass
+
+    def test_basic_error(self):
+        e = AnsibleError(self.message)
+        self.assertEqual(e.message, self.message)
+
+    def test_error_with_object(self):
+        obj = AnsibleBaseYAMLObject()
+        obj._data_source   = 'foo.yml'
+        obj._line_number   = 1
+        obj._column_number = 1
+
+        m = mock_open()
+        m.return_value.readlines.return_value = ['this is line 1\n', 'this is line 2\n', 'this is line 3\n']
+        with patch('{0}.open'.format(BUILTINS), m):
+            e = AnsibleError(self.message, obj)
+
+        self.assertEqual(e.message, 'this is the error message\nThe error occurred on line 1 of the file foo.yml:\nthis is line 1\n^')
diff --git a/v2/test/parsing/__init__.py b/v2/test/parsing/__init__.py
new file mode 100644
index 00000000000..1f84012e014
--- /dev/null
+++ b/v2/test/parsing/__init__.py
@@ -0,0 +1,16 @@
+# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
diff --git a/v2/test/parsing/test_general.py b/v2/test/parsing/test_general.py
new file mode 100644
index 00000000000..377aa886935
--- /dev/null
+++ b/v2/test/parsing/test_general.py
@@ -0,0 +1,102 @@
+# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
+
+from ..compat import unittest
+from ansible.parsing import load
+from ansible.errors import AnsibleParserError
+
+import json
+
+from io import FileIO
+
+class MockFile(FileIO):
+
+    def __init__(self, ds, method='json'):
+        self.ds = ds
+        self.method = method
+
+    def read(self):
+        if method == 'json':
+            return json.dumps(ds)
+        elif method == 'yaml':
+            return yaml.dumps(ds)
+        elif method == 'fail':
+            return """
+            AAARGGGGH
+               THIS WON'T PARSE !!!
+                  NOOOOOOOOOOOOOOOOOO
+            """
+        else:
+            raise Exception("untestable serializer")
+
+    def close(self):
+        pass
+
+class TestGeneralParsing(unittest.TestCase):
+
+    def __init__(self):
+        pass
+
+    def setUp(self):
+        pass
+
+    def tearDown(self):
+        pass
+
+    def parse_json_from_string(self):
+        input = """
+        {
+            "asdf" : "1234",
+            "jkl" : 5678
+        }
+        """
+        output = load(input)
+        self.assertEqual(output['asdf'], '1234')
+        self.assertEqual(output['jkl'], 5678)
+
+    def parse_json_from_file(self):
+        output = load(MockFile(dict(a=1,b=2,c=3)),'json')
+        self.assertEqual(ouput, dict(a=1,b=2,c=3))
+
+    def parse_yaml_from_dict(self):
+        input = """
+        asdf: '1234'
+        jkl: 5678
+        """
+        output = load(input)
+        self.assertEqual(output['asdf'], '1234')
+        self.assertEqual(output['jkl'], 5678)
+
+    def parse_yaml_from_file(self):
+        output = load(MockFile(dict(a=1,b=2,c=3),'yaml'))
+        self.assertEqual(output, dict(a=1,b=2,c=3))
+
+    def parse_fail(self):
+        input = """
+        TEXT
+            ***
+               NOT VALID
+        """
+        self.assertRaises(load(input), AnsibleParserError)
+
+    def parse_fail_from_file(self):
+        self.assertRaises(load(MockFile(None,'fail')), AnsibleParserError)
+
+    def parse_fail_invalid_type(self):
+        self.assertRaises(3000, AnsibleParsingError)
+        self.assertRaises(dict(a=1,b=2,c=3), AnsibleParserError)
+
diff --git a/v2/test/parsing/test_mod_args.py b/v2/test/parsing/test_mod_args.py
new file mode 100644
index 00000000000..b52b6f9cc3e
--- /dev/null
+++ b/v2/test/parsing/test_mod_args.py
@@ -0,0 +1,104 @@
+# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
+
+from ansible.parsing.mod_args import ModuleArgsParser
+
+from .. compat import CompatTestCase
+
+class TestModArgsDwim(CompatTestCase):
+
+    # TODO: add tests that construct ModuleArgsParser with a task reference
+    # TODO: verify the AnsibleError raised on failure knows the task
+    #       and the task knows the line numbers
+
+    def setUp(self):
+        self.m = ModuleArgsParser()
+        pass
+
+    def _debug(self, mod, args, to):
+        print("RETURNED module = {0}".format(mod))
+        print("           args = {0}".format(args))
+        print("             to = {0}".format(to))
+
+    def tearDown(self):
+        pass
+
+    def test_basic_shell(self):
+        mod, args, to = self.m.parse(dict(shell='echo hi'))
+        self._debug(mod, args, to)
+        self.assertEqual(mod, 'command')
+        self.assertEqual(args, dict(
+                                _raw_params = 'echo hi',
+                                _uses_shell = True,
+                        ))
+        self.assertIsNone(to)
+
+    def test_basic_command(self):
+        mod, args, to = self.m.parse(dict(command='echo hi'))
+        self._debug(mod, args, to)
+        self.assertEqual(mod, 'command')
+        self.assertEqual(args, dict(
+                                _raw_params = 'echo hi',
+                        ))
+        self.assertIsNone(to)
+
+    def test_shell_with_modifiers(self):
+        mod, args, to = self.m.parse(dict(shell='/bin/foo creates=/tmp/baz removes=/tmp/bleep'))
+        self._debug(mod, args, to)
+        self.assertEqual(mod, 'command')
+        self.assertEqual(args, dict(
+                                creates     = '/tmp/baz',
+                                removes     = '/tmp/bleep',
+                                _raw_params = '/bin/foo',
+                                _uses_shell = True,
+                        ))
+        self.assertIsNone(to)
+
+    def test_normal_usage(self):
+        mod, args, to = self.m.parse(dict(copy='src=a dest=b'))
+        self._debug(mod, args, to)
+        self.assertEqual(mod, 'copy')
+        self.assertEqual(args, dict(src='a', dest='b'))
+        self.assertIsNone(to)
+
+    def test_complex_args(self):
+        mod, args, to = self.m.parse(dict(copy=dict(src='a', dest='b')))
+        self._debug(mod, args, to)
+        self.assertEqual(mod, 'copy')
+        self.assertEqual(args, dict(src='a', dest='b'))
+        self.assertIsNone(to)
+
+    def test_action_with_complex(self):
+        mod, args, to = self.m.parse(dict(action=dict(module='copy', src='a', dest='b')))
+        self._debug(mod, args, to)
+        self.assertEqual(mod, 'copy')
+        self.assertEqual(args, dict(src='a', dest='b'))
+        self.assertIsNone(to)
+
+    def test_action_with_complex_and_complex_args(self):
+        mod, args, to = self.m.parse(dict(action=dict(module='copy', args=dict(src='a', dest='b'))))
+        self._debug(mod, args, to)
+        self.assertEqual(mod, 'copy')
+        self.assertEqual(args, dict(src='a', dest='b'))
+        self.assertIsNone(to)
+
+    def test_local_action_string(self):
+        mod, args, to = self.m.parse(dict(local_action='copy src=a dest=b'))
+        self._debug(mod, args, to)
+        self.assertEqual(mod, 'copy')
+        self.assertEqual(args, dict(src='a', dest='b'))
+        self.assertIs(to, 'localhost')
diff --git a/v2/test/parsing/test_mod_args.py.py3 b/v2/test/parsing/test_mod_args.py.py3
new file mode 100644
index 00000000000..b52b6f9cc3e
--- /dev/null
+++ b/v2/test/parsing/test_mod_args.py.py3
@@ -0,0 +1,104 @@
+# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
+
+from ansible.parsing.mod_args import ModuleArgsParser
+
+from .. compat import CompatTestCase
+
+class TestModArgsDwim(CompatTestCase):
+
+    # TODO: add tests that construct ModuleArgsParser with a task reference
+    # TODO: verify the AnsibleError raised on failure knows the task
+    #       and the task knows the line numbers
+
+    def setUp(self):
+        self.m = ModuleArgsParser()
+        pass
+
+    def _debug(self, mod, args, to):
+        print("RETURNED module = {0}".format(mod))
+        print("           args = {0}".format(args))
+        print("             to = {0}".format(to))
+
+    def tearDown(self):
+        pass
+
+    def test_basic_shell(self):
+        mod, args, to = self.m.parse(dict(shell='echo hi'))
+        self._debug(mod, args, to)
+        self.assertEqual(mod, 'command')
+        self.assertEqual(args, dict(
+                                _raw_params = 'echo hi',
+                                _uses_shell = True,
+                        ))
+        self.assertIsNone(to)
+
+    def test_basic_command(self):
+        mod, args, to = self.m.parse(dict(command='echo hi'))
+        self._debug(mod, args, to)
+        self.assertEqual(mod, 'command')
+        self.assertEqual(args, dict(
+                                _raw_params = 'echo hi',
+                        ))
+        self.assertIsNone(to)
+
+    def test_shell_with_modifiers(self):
+        mod, args, to = self.m.parse(dict(shell='/bin/foo creates=/tmp/baz removes=/tmp/bleep'))
+        self._debug(mod, args, to)
+        self.assertEqual(mod, 'command')
+        self.assertEqual(args, dict(
+                                creates     = '/tmp/baz',
+                                removes     = '/tmp/bleep',
+                                _raw_params = '/bin/foo',
+                                _uses_shell = True,
+                        ))
+        self.assertIsNone(to)
+
+    def test_normal_usage(self):
+        mod, args, to = self.m.parse(dict(copy='src=a dest=b'))
+        self._debug(mod, args, to)
+        self.assertEqual(mod, 'copy')
+        self.assertEqual(args, dict(src='a', dest='b'))
+        self.assertIsNone(to)
+
+    def test_complex_args(self):
+        mod, args, to = self.m.parse(dict(copy=dict(src='a', dest='b')))
+        self._debug(mod, args, to)
+        self.assertEqual(mod, 'copy')
+        self.assertEqual(args, dict(src='a', dest='b'))
+        self.assertIsNone(to)
+
+    def test_action_with_complex(self):
+        mod, args, to = self.m.parse(dict(action=dict(module='copy', src='a', dest='b')))
+        self._debug(mod, args, to)
+        self.assertEqual(mod, 'copy')
+        self.assertEqual(args, dict(src='a', dest='b'))
+        self.assertIsNone(to)
+
+    def test_action_with_complex_and_complex_args(self):
+        mod, args, to = self.m.parse(dict(action=dict(module='copy', args=dict(src='a', dest='b'))))
+        self._debug(mod, args, to)
+        self.assertEqual(mod, 'copy')
+        self.assertEqual(args, dict(src='a', dest='b'))
+        self.assertIsNone(to)
+
+    def test_local_action_string(self):
+        mod, args, to = self.m.parse(dict(local_action='copy src=a dest=b'))
+        self._debug(mod, args, to)
+        self.assertEqual(mod, 'copy')
+        self.assertEqual(args, dict(src='a', dest='b'))
+        self.assertIs(to, 'localhost')
diff --git a/v2/test/parsing/yaml/__init__.py b/v2/test/parsing/yaml/__init__.py
new file mode 100644
index 00000000000..1f84012e014
--- /dev/null
+++ b/v2/test/parsing/yaml/__init__.py
@@ -0,0 +1,16 @@
+# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
diff --git a/v2/test/parsing/yaml/test_yaml.py b/v2/test/parsing/yaml/test_yaml.py
new file mode 100644
index 00000000000..b8d7771c7cb
--- /dev/null
+++ b/v2/test/parsing/yaml/test_yaml.py
@@ -0,0 +1,96 @@
+# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
+
+from ..compat import unittest
+
+from yaml.scanner import ScannerError
+
+from ansible.parsing.yaml import safe_load
+from ansible.parsing.yaml.objects import AnsibleMapping
+
+# a single dictionary instance
+data1 = '''---
+key: value
+'''
+
+# multiple dictionary instances
+data2 = '''---
+- key1: value1
+- key2: value2
+
+- key3: value3
+
+
+- key4: value4
+'''
+
+# multiple dictionary instances with other nested
+# dictionaries contained within those
+data3 = '''---
+- key1:
+    subkey1: subvalue1
+    subkey2: subvalue2
+    subkey3:
+      subsubkey1: subsubvalue1
+- key2:
+    subkey4: subvalue4
+- list1:
+  - list1key1: list1value1
+    list1key2: list1value2
+    list1key3: list1value3
+'''
+
+bad_data1 = '''---
+foo: bar
+  bam: baz
+'''
+
+class TestSafeLoad(unittest.TestCase):
+
+    def setUp(self):
+        pass
+
+    def tearDown(self):
+        pass
+
+    def test_safe_load_bad(self):
+        # test the loading of bad yaml data
+        self.assertRaises(ScannerError, safe_load, bad_data1)
+
+    def test_safe_load(self):
+        # test basic dictionary
+        res = safe_load(data1)
+        self.assertEqual(type(res), AnsibleMapping)
+        self.assertEqual(res._line_number, 2)
+
+        # test data with multiple dictionaries
+        res = safe_load(data2)
+        self.assertEqual(len(res), 4)
+        self.assertEqual(res[0]._line_number, 2)
+        self.assertEqual(res[1]._line_number, 3)
+        self.assertEqual(res[2]._line_number, 5)
+        self.assertEqual(res[3]._line_number, 8)
+
+        # test data with multiple sub-dictionaries
+        res = safe_load(data3)
+        self.assertEqual(len(res), 3)
+        self.assertEqual(res[0]._line_number, 2)
+        self.assertEqual(res[1]._line_number, 7)
+        self.assertEqual(res[2]._line_number, 9)
+        self.assertEqual(res[0]['key1']._line_number, 3)
+        self.assertEqual(res[1]['key2']._line_number, 8)
+        self.assertEqual(res[2]['list1'][0]._line_number, 10)
diff --git a/v2/test/playbook/__init__.py b/v2/test/playbook/__init__.py
new file mode 100644
index 00000000000..1f84012e014
--- /dev/null
+++ b/v2/test/playbook/__init__.py
@@ -0,0 +1,16 @@
+# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
diff --git a/v2/test/playbook/test_task.py b/v2/test/playbook/test_task.py
new file mode 100644
index 00000000000..ec7ce9012e8
--- /dev/null
+++ b/v2/test/playbook/test_task.py
@@ -0,0 +1,84 @@
+# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
+
+from ansible.playbook.task import Task
+from ..compat import unittest
+
+basic_shell_task = dict(
+   name  = 'Test Task',
+   shell = 'echo hi'
+)
+
+kv_shell_task = dict(
+   action = 'shell echo hi'
+)
+
+class TestTask(unittest.TestCase):
+
+    def setUp(self):
+        pass
+
+    def tearDown(self):
+        pass
+
+    def test_construct_empty_task(self):
+        t = Task()
+
+    def test_construct_task_with_role(self):
+        pass
+
+    def test_construct_task_with_block(self):
+        pass
+
+    def test_construct_task_with_role_and_block(self):
+        pass
+
+    def test_load_task_simple(self):
+        t = Task.load(basic_shell_task)
+        assert t is not None
+        self.assertEqual(t.name, basic_shell_task['name'])
+        self.assertEqual(t.action, 'command')
+        self.assertEqual(t.args, dict(_raw_params='echo hi', _uses_shell=True))
+
+    def test_load_task_kv_form(self):
+        t = Task.load(kv_shell_task)
+        print("task action is %s" % t.action)
+        self.assertEqual(t.action, 'command')
+        self.assertEqual(t.args, dict(_raw_params='echo hi', _uses_shell=True))
+
+    def test_task_auto_name(self):
+        assert 'name' not in kv_shell_task
+        t = Task.load(kv_shell_task)
+        #self.assertEqual(t.name, 'shell echo hi')
+
+    def test_task_auto_name_with_role(self):
+        pass
+
+    def test_load_task_complex_form(self):
+        pass
+
+    def test_can_load_module_complex_form(self):
+        pass
+
+    def test_local_action_implies_delegate(self):
+        pass
+
+    def test_local_action_conflicts_with_delegate(self):
+        pass
+
+    def test_delegate_to_parses(self):
+        pass
diff --git a/v2/test/test.yml b/v2/test/test.yml
new file mode 100644
index 00000000000..299b66610d1
--- /dev/null
+++ b/v2/test/test.yml
@@ -0,0 +1,2 @@
+- name: Test
+filename: /usr/café/�/are_doing_this_to_me