Repository: RedHatInsights/insights-core

Issue:
Exception should be thrown when adding filters to a non-filterable parser
Currently when applying a filter to a non-filterable parser or a combiner that does not depend on any filterable components, no exception will be thrown, this is not correct/expected.

E.g.
```
In [1]: from insights.core.filters import add_filter

In [2]: from insights.parsers.hostname import Hostname as Hostname_Parser

In [3]: from insights.combiners.hostname import Hostname as Hostname_Combiner

In [4]: add_filter(Hostname_Parser, 'test')

In [5]: add_filter(Hostname_Combiner, 'test')
```

But in fact, in the above examples, the specs of `Hostname` Parser and Combiner are all non-filterable.


Discussion:

Resolving patch:
diff --git a/insights/core/filters.py b/insights/core/filters.py
--- a/insights/core/filters.py
+++ b/insights/core/filters.py
@@ -86,11 +86,18 @@ def inner(component, patterns):
         FILTERS[component] |= patterns
 
     if not plugins.is_datasource(component):
-        for dep in dr.run_order(dr.get_dependency_graph(component)):
-            if plugins.is_datasource(dep):
-                d = dr.get_delegate(dep)
-                if d.filterable:
-                    inner(dep, patterns)
+        deps = dr.run_order(dr.get_dependency_graph(component))
+        if deps:
+            filterable_deps = [
+                dep for dep in deps if (plugins.is_datasource(dep) and
+                                        dr.get_delegate(dep).filterable)
+            ]
+            # At least one dependency component be filterable
+            if not filterable_deps:
+                raise Exception("Filters aren't applicable to %s." % dr.get_name(component))
+
+            for dep in filterable_deps:
+                inner(dep, patterns)
     else:
         delegate = dr.get_delegate(component)
 


Test patch:
diff --git a/insights/tests/test_filters.py b/insights/tests/test_filters.py
--- a/insights/tests/test_filters.py
+++ b/insights/tests/test_filters.py
@@ -4,6 +4,7 @@
 from collections import defaultdict
 
 from insights import datasource
+from insights.combiners.hostname import Hostname
 from insights.core import filters
 from insights.core.spec_factory import DatasourceProvider, RegistryPoint, SpecSet
 from insights.parsers.ps import PsAux, PsAuxcww
@@ -108,20 +109,19 @@ def test_add_filter_to_parser_patterns_list():
     assert not parser_filters
 
 
-def test_add_filter_to_parser_non_filterable():
-    filter_string = "bash"
-    filters.add_filter(PsAuxcww, filter_string)
+def test_add_filter_exception_not_filterable():
+    with pytest.raises(Exception):
+        filters.add_filter(Specs.ps_auxcww, "bash")
 
-    spec_filters = filters.get_filters(Specs.ps_auxcww)
-    assert not spec_filters
 
-    parser_filters = filters.get_filters(PsAuxcww)
-    assert not parser_filters
+def test_add_filter_exception_parser_non_filterable():
+    with pytest.raises(Exception):
+        filters.add_filter(PsAuxcww, 'bash')
 
 
-def test_add_filter_exception_not_filterable():
+def test_add_filter_exception_combiner_non_filterable():
     with pytest.raises(Exception):
-        filters.add_filter(Specs.ps_auxcww, "bash")
+        filters.add_filter(Hostname, "bash")
 
 
 def test_add_filter_exception_raw():