Improved merging of null-values

YAML returns 'None' when a key is parsed without a value. This is
properly handled by a95eaa35f5c48417420fe37472d8148fdbf5ddd5, except for
the recursive dict merger, which shouldn't overwrite existing data
structures when None is encountered. The solution is simply to provide
appropriate policy entries for when the second value is a NoneType.

Signed-off-by: martin f. krafft <madduck@madduck.net>
diff --git a/mergers/dict/recursive_policy_update.py b/mergers/dict/recursive_policy_update.py
index 01dfccb..e280889 100644
--- a/mergers/dict/recursive_policy_update.py
+++ b/mergers/dict/recursive_policy_update.py
@@ -13,10 +13,15 @@
     def __init__(self, policy=None):
         super(DictRecursivePolicyUpdate, self).__init__()
         if policy is None:
-            policy = {(dict,dict) : self.merge,
-                      (list,list) : lambda x,y: x+y,
-                      (dict,list) : lambda x,y: self.merge(x, dict(y)),
-                      None        : lambda x,y: y
+            first = lambda first, second: first
+            second = lambda first, second: second
+
+            policy = {(dict,dict)       : self.merge,
+                      (list,list)       : lambda x,y: x+y,
+                      (dict,list)       : lambda x,y: self.merge(x, dict(y)),
+                      (dict,type(None)) : first,
+                      (list,type(None)) : first,
+                      None              : second
                      }
         self._policy = policy
 
@@ -27,8 +32,8 @@
         ret = first.copy()
         for k,v in second.iteritems():
             if k in ret:
-                pfn = self._policy.get((type(ret[k]), type(v)),
-                                       self._policy.get(None))
+                lookup = (type(ret[k]), type(v))
+                pfn = self._policy.get(lookup, self._policy.get(None))
                 ret[k] = pfn(ret[k], v)
             else:
                 ret[k] = v
diff --git a/storage/yaml_fs/tests/classes/debiannode.yml b/storage/yaml_fs/tests/classes/debiannode.yml
index 43e35e4..84837ff 100644
--- a/storage/yaml_fs/tests/classes/debiannode.yml
+++ b/storage/yaml_fs/tests/classes/debiannode.yml
@@ -2,3 +2,6 @@
 - basenode
 applications:
 - apt
+parameters:
+  apt:
+    mirror_base: http://http.debian.net
diff --git a/storage/yaml_fs/tests/nodes/red.yml b/storage/yaml_fs/tests/nodes/red.yml
index 5fe618d..051d0f5 100644
--- a/storage/yaml_fs/tests/nodes/red.yml
+++ b/storage/yaml_fs/tests/nodes/red.yml
@@ -3,6 +3,7 @@
 - hosted@zurich
 - webserver
 parameters:
+  apt:  # null-value must not override inherited dictionary
   motd:
     greeting: This node is $nodename
   colour: red
diff --git a/storage/yaml_fs/tests/test_yaml_fs.py b/storage/yaml_fs/tests/test_yaml_fs.py
index bb4ba12..89ae294 100644
--- a/storage/yaml_fs/tests/test_yaml_fs.py
+++ b/storage/yaml_fs/tests/test_yaml_fs.py
@@ -63,3 +63,7 @@
             assert 'applications' in node
             assert 'classes' in node
             assert 'parameters' in node
+
+    def test_merge_empty_dict(self):
+        node = self._storage.nodeinfo(HOSTS[0])
+        assert node['parameters'].get('apt') is not None