<div dir="ltr">Hello,<br><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Apr 20, 2015 at 3:59 AM, Christian Boltz <span dir="ltr"><<a href="mailto:apparmor@cboltz.de" target="_blank">apparmor@cboltz.de</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Hello,<br>
<br>
Am Sonntag, 19. April 2015 schrieb Kshitij Gupta:<br>
<span class="">> On Sat, Apr 18, 2015 at 2:51 AM, Christian Boltz wrote:<br>
> > Am Dienstag, 14. April 2015 schrieb Christian Boltz:<br>
> > > this patch adds utils/test/test-network.py with tests for<br>
> > > NetworkRule<br>
> > > and NetworkRuleset.<br>
> > ><br>
> > > The tests are hopefully self-explaining, so let me just mention<br>
> > > the<br>
> > > most important things:<br>
> > > - I started to play with namedtuple, which looks very useful (see<br>
><br>
> Interesting! Like a dictionary but without any overhead.<br>
<br>
</span>The important thing is that it allows to have named elements without the<br>
need to repeat the names all the time. And that's something really<br>
useful, especially when writing tests table-style to get sane line<br>
lengths ;-)<br>
<br>
That said - we have to thank Steve who gave a pointer to namedtuple some<br>
weeks ago.<br>
<span class=""><br>
> > +import unittest<br>
> > +from common_test import AATest, setup_all_loops<br>
> > +from collections import namedtuple<br>
><br>
> Nitpick: a non standard import surrounding apparmor specific import is<br>
> odd. Probably could re-use some shuffling around/separation.<br>
> quoting PEP 8 [1]:<br>
> "Imports should be grouped in the following order:<br>
><br>
</span>>    1. standard library imports<br>
>    2. related third party imports<br>
>    3. local application/library specific imports<br>
<span class="">><br>
>  You should put a blank line between each group of imports."<br>
<br>
</span>Hmm, that's an interesting question.<br>
<br>
While I agree that those rules make sense for "normal" code, I'm not<br>
sure if they make sense for our testcases.<br>
<br>
Basically the order I'm using is:<br>
    1. libraries needed to setup and run the tests (sooner or later, all<br>
       tests will have those imports)<br>
    2. the things we want to test<br>
    3. additional libs needed for some tests (for example 're', even if<br>
       that vanished by moving test_parse_profile_invalid() to<br>
       test-baserule.py)<br>
<br></blockquote><div>I'm find with this reasoning for not following the PEP 8.<br></div><div>It'll be interesting to see what a pyflakes run says about it.<br><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
Inside the first group, changing the order according to PEP 8 can't<br>
hurt, so I'm moving namedtuple a line upwards.<br>
<span class=""><br>
> > +from apparmor.rule.network import NetworkRule, NetworkRuleset<br>
> > +from apparmor.rule import BaseRule, parse_modifiers<br>
> > +from apparmor.common import AppArmorException, AppArmorBug<br>
> > +from apparmor.logparser import ReadLog<br>
> > +<br>
> > +import re<br>
> > +<br>
> > +exp = namedtuple('exp', ['audit', 'allow_keyword', 'deny',<br>
> > 'comment', +        'domain', 'all_domains', 'type_or_protocol',<br>
> > 'all_type_or_protocols'])<br>
><br>
> Didn't know about this. Pretty cool for readability.<br>
<br>
</span>Indeed :-)  (as long as you add a comment as "headline" when using it)<br>
<span class=""><br>
> > +class NetworkTestParseFromLog(NetworkTest):<br>
> > +    def test_net_from_log(self):<br>
> > +        parser = ReadLog('', '', '', '', '')<br>
> > +        event = 'type=AVC msg=audit(1428699242.551:386):<br>
> > apparmor="DENIED" operation="create" profile="/bin/ping" pid=10589<br>
> > comm="ping" family="inet" sock_type="raw" protocol=1'<br>
> > +<br>
> > +        parsed_event = parser.parse_event(event)<br>
> > +<br>
> > +        self.assertEqual(parsed_event, {<br>
> > +            'request_mask': None,<br>
> > +            'denied_mask': None,<br>
><br>
> you switched from set() to None between the two versions of this<br>
> patch?<br>
<br>
</span>Yes, that's caused by the logparser.py r3009 changes, which moved the<br>
code that parses request_mask and denied_mask to add_event_to_tree()<br>
(and does it only for file events).<br>
<br>
Sorry, I should have mentioned that in my v2 mail.<br>
<span class=""><br>
> > +        self._compare_obj(obj, expected)<br>
> > +<br>
> > +        self.assertEqual(obj.get_raw(1), '  network inet raw,')<br>
><br>
> why obj.get_raw(1) and not assertEqual on obj.raw_rule? The depth code<br>
> in get_raw() should be already be under tests elsewhere, seems<br>
> redundant? look below: comment about parse_modifiers<br>
<br>
</span>I prefer to test against the public functions - obj.raw_rule is just an<br>
implementation detail that could in theory change without breaking<br>
something.<br>
<br>
Besides that - in test_write_manually() obj.raw_rule is empty ;-)<br>
<span class=""><br>
> > +class InvalidNetworkInit(AATest):<br>
> > +    tests = [<br>
<br>
</span>> > +        ([dict(), 'tcp'            ]     , AppArmorBug), # wrong<br>
<span class="">> > type for domain<br>
> > +        (['inet', dict()           ]    , AppArmorBug), # wrong<br>
> > type for type_or_protocol<br>
><br>
> Nitpick: would it be better/correct to use None instead of dict()<br>
> here? using dict() or list() seems arbitrary to me (I maybe wrong)?<br>
<br>
</span>Sounds like a philosophical question - what is a correct invalid value? ;-)<br>
<br>
Basically we can use everything that is not a string and not<br>
NetworkRule.ALL as invalid parameter, so I just picked one.<br>
Oh, and I just added the "None" variant as additional tests.<br>
<span class=""><br>
> > +    def test_parse_modifiers_invalid(self):<br>
> > +        regex =<br>
> > re.compile('^\s*(?P<audit>audit\s+)?(?P<allow>allow\s+|deny\s+|inval<br>
> > id\s+)?') +        matches = regex.search('audit invalid ')<br>
> > +<br>
> > +        with self.assertRaises(AppArmorBug):<br>
> > +            parse_modifiers(matches)<br>
><br>
> This test is redundant as its already present in test-capability. Also<br>
> this test should instead be located somewhere where the tests for the<br>
> base classes are located as parse_modifiers is defined with them.<br>
<br>
</span>Indeed. I removed it from test-network.py (which also means to remove<br>
the import for parse_modifiers and re).<br>
<br>
I just sent a separate patch to move it from test-capability.py to<br>
test-baserule.py (the patch to add test-baserule.py is still pending,<br>
reviewing it should be easy ;-)<br>
<span class=""><br>
> > +    def test_write_manually(self):<br>
> > +        obj = NetworkRule('inet', 'stream', allow_keyword=True)<br>
> > +<br>
> > +        expected = '    allow network inet stream,'<br>
> > +<br>
> > +        self.assertEqual(expected, obj.get_clean(2), 'unexpected<br>
> > clean rule')<br>
> > +        self.assertEqual(expected, obj.get_raw(2), 'unexpected raw<br>
> > rule')<br>
> As stated in rule/__init__.py, subclasses needed to implement<br>
> get_clean so its fair that get_clean should have tests here, however,<br>
> get_raw is not being implemented in capability or network rule<br>
> classes and it seems redundant to have tests for the same at both<br>
> places. I feel we can do away with tests for these methods in every<br>
> rule class and have them centralised place (tests for the __init__<br>
> stuff), unless a class overrides it. Opinions?<br>
<br>
</span>In theory, I agree - yes, it seems redundant.<br>
<br>
In practise, I want to keep that safety net - and I also want to test<br>
with all rule types to make sure we don't accidently break writing the<br>
raw rule somewhere.<br>
<span class=""><br></span></blockquote><div>Its okay I guess until we start having too much redundant tests(if there's such a thing) for safety.<br><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span class="">
> In general the above patch looks good specially given the 100%<br>
> coverage stat (will coverage % be effected if we move the get_raw<br>
> stuff to some other place?).<br>
<br>
</span>Probably not, but as I said, I prefer not to move it.<br>
<br>
BTW: Coverage stats are nice, but don't tell everything. Just as an<br>
example - if you test a complex regex with one example, you'll have<br>
100% coverage, but this doesn't mean that the regex is correct for all<br>
usecases.<br>
<span class=""><br>
> Note: I've used to the existing capability rule tests/classes for<br>
> reference given it went through many rounds of iteration before being<br>
> committed.<br>
<br>
</span>Then you probably also noticed that I've used test-capability.py as<br>
base for test-network.py - basically I started with<br></blockquote><div>Indeed. <br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
    sed 's/^/# / ; s/capability/network/' < test-capability.py > test-network.py<br>
and then did some more changes and removed the # again.<br>
<br>
Of course, that's the simplified version - there are more differences<br>
besides those replacements, and also some improvements like using<br>
namedtuple.<br>
<span class=""><br>
> It wouldn't hurt to have second set of eyes look at this patch series.<br>
><br>
> However, I'm willing to ack this patch set once Christian responds on<br>
> the above queries.<br>
<br>
</span>:-)<br>
<span class=""><br>
> [1]- <a href="https://www.python.org/dev/peps/pep-0008/#imports" target="_blank">https://www.python.org/dev/peps/pep-0008/#imports</a><br>
><br>
> Follow-up read:<br>
> <a href="https://www.python.org/dev/peps/pep-0328/#guido-s-decision" target="_blank">https://www.python.org/dev/peps/pep-0328/#guido-s-decision</a><br>
<br>
</span>That sounds like another can of worms... ;-)<br>
<br></blockquote><div>;-) <br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
That all said, here's the updated patch.<br>
<span class=""><br>
<br>
[ 45-add-tests-for-NetworkRule.diff ]<br>
<br>
=== added file utils/test/test-network.py<br>
</span>--- utils/test/test-network.py  2015-04-20 00:15:46.001752247 +0200<br>
+++ utils/test/test-network.py  2015-04-20 00:17:43.852948920 +0200<br>
@@ -0,0 +1,421 @@<br>
<span class="">+#!/usr/bin/env python<br>
+# ----------------------------------------------------------------------<br>
+#    Copyright (C) 2015 Christian Boltz <<a href="mailto:apparmor@cboltz.de">apparmor@cboltz.de</a>><br>
+#<br>
+#    This program is free software; you can redistribute it and/or<br>
+#    modify it under the terms of version 2 of the GNU General Public<br>
+#    License as published by the Free Software Foundation.<br>
+#<br>
+#    This program is distributed in the hope that it will be useful,<br>
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of<br>
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the<br>
+#    GNU General Public License for more details.<br>
+#<br>
+# ----------------------------------------------------------------------<br>
+<br>
+import unittest<br>
</span>+from collections import namedtuple<br>
<span class="">+from common_test import AATest, setup_all_loops<br>
</span><span class="">+<br>
+from apparmor.rule.network import NetworkRule, NetworkRuleset<br>
+from apparmor.rule import BaseRule<br>
</span><span class="">+from apparmor.common import AppArmorException, AppArmorBug<br>
+from apparmor.logparser import ReadLog<br>
+<br>
</span><span class="">+exp = namedtuple('exp', ['audit', 'allow_keyword', 'deny', 'comment',<br>
+        'domain', 'all_domains', 'type_or_protocol', 'all_type_or_protocols'])<br>
</span><div><div class="h5">+<br>
+# --- tests for single NetworkRule --- #<br>
+<br>
+class NetworkTest(AATest):<br>
+    def _compare_obj(self, obj, expected):<br>
+        self.assertEqual(expected.allow_keyword, obj.allow_keyword)<br>
+        self.assertEqual(expected.audit, obj.audit)<br>
+        self.assertEqual(expected.domain, obj.domain)<br>
+        self.assertEqual(expected.type_or_protocol, obj.type_or_protocol)<br>
+        self.assertEqual(expected.all_domains, obj.all_domains)<br>
+        self.assertEqual(expected.all_type_or_protocols, obj.all_type_or_protocols)<br>
+        self.assertEqual(expected.deny, obj.deny)<br>
+        self.assertEqual(expected.comment, obj.comment)<br>
+<br>
+class NetworkTestParse(NetworkTest):<br>
+    tests = [<br>
+        # rawrule                                     audit  allow  deny   comment        domain    all?   type/proto  all?<br>
+        ('network,'                             , exp(False, False, False, ''           , None  ,   True , None     , True )),<br>
+        ('network inet,'                        , exp(False, False, False, ''           , 'inet',   False, None     , True )),<br>
+        ('network inet stream,'                 , exp(False, False, False, ''           , 'inet',   False, 'stream' , False)),<br>
+        ('deny network inet stream, # comment'  , exp(False, False, True , ' # comment' , 'inet',   False, 'stream' , False)),<br>
+        ('audit allow network tcp,'             , exp(True , True , False, ''           , None  ,   True , 'tcp'    , False)),<br>
+    ]<br>
+<br>
+    def _run_test(self, rawrule, expected):<br>
+        obj = NetworkRule.parse(rawrule)<br>
+        self.assertEqual(rawrule.strip(), obj.raw_rule)<br>
+        self._compare_obj(obj, expected)<br>
+<br>
+class NetworkTestParseInvalid(NetworkTest):<br>
+    tests = [<br>
+        ('network stream,'                  , AppArmorException), # domain missing<br>
+        ('network foo,'                     , AppArmorException),<br>
+        ('network foo bar,'                 , AppArmorException),<br>
+        ('network foo tcp,'                 , AppArmorException),<br>
+        ('network inet bar,'                , AppArmorException),<br>
+    ]<br>
+<br>
+    def _run_test(self, rawrule, expected):<br>
+        with self.assertRaises(expected):<br>
+            NetworkRule.parse(rawrule)<br>
+<br>
+class NetworkTestParseFromLog(NetworkTest):<br>
+    def test_net_from_log(self):<br>
+        parser = ReadLog('', '', '', '', '')<br>
+        event = 'type=AVC msg=audit(1428699242.551:386): apparmor="DENIED" operation="create" profile="/bin/ping" pid=10589 comm="ping" family="inet" sock_type="raw" protocol=1'<br>
+<br>
+        parsed_event = parser.parse_event(event)<br>
+<br>
+        self.assertEqual(parsed_event, {<br>
+            'request_mask': None,<br>
+            'denied_mask': None,<br>
</div></div><div><div class="h5">+            'error_code': 0,<br>
+            'family': 'inet',<br>
+            'magic_token': 0,<br>
+            'parent': 0,<br>
+            'profile': '/bin/ping',<br>
+            'protocol': 'icmp',<br>
+            'sock_type': 'raw',<br>
+            'operation': 'create',<br>
+            'resource': None,<br>
+            'info': None,<br>
+            'aamode': 'REJECTING',<br>
+            'time': 1428699242,<br>
+            'active_hat': None,<br>
+            'pid': 10589,<br>
+            'task': 0,<br>
+            'attr': None,<br>
+            'name2': None,<br>
+            'name': None,<br>
+        })<br>
+<br>
+        obj = NetworkRule(parsed_event['family'], parsed_event['sock_type'], log_event=parsed_event)<br>
+<br>
+        #              audit  allow  deny   comment        domain    all?   type/proto  all?<br>
+        expected = exp(False, False, False, ''           , 'inet',   False, 'raw'    , False)<br>
+<br>
+        self._compare_obj(obj, expected)<br>
+<br>
+        self.assertEqual(obj.get_raw(1), '  network inet raw,')<br>
</div></div><div><div class="h5">+<br>
+<br>
+class NetworkFromInit(NetworkTest):<br>
+    tests = [<br>
+        # NetworkRule object                                  audit  allow  deny   comment        domain    all?   type/proto  all?<br>
+        (NetworkRule('inet', 'raw', deny=True)          , exp(False, False, True , ''           , 'inet',   False, 'raw'    , False)),<br>
+        (NetworkRule('inet', 'raw')                     , exp(False, False, False, ''           , 'inet',   False, 'raw'    , False)),<br>
+        (NetworkRule('inet', NetworkRule.ALL)           , exp(False, False, False, ''           , 'inet',   False, None     , True )),<br>
+        (NetworkRule(NetworkRule.ALL, NetworkRule.ALL)  , exp(False, False, False, ''           , None  ,   True , None     , True )),<br>
+        (NetworkRule(NetworkRule.ALL, 'tcp')            , exp(False, False, False, ''           , None  ,   True , 'tcp'    , False)),<br>
+    ]<br>
+<br>
+    def _run_test(self, obj, expected):<br>
+        self._compare_obj(obj, expected)<br>
+<br>
+<br>
+class InvalidNetworkInit(AATest):<br>
+    tests = [<br>
+        # init params                     expected exception<br>
+        (['inet', ''               ]    , AppArmorBug), # empty type_or_protocol<br>
+        ([''    , 'tcp'            ]    , AppArmorBug), # empty domain<br>
+        (['    ', 'tcp'            ]    , AppArmorBug), # whitespace domain<br>
+        (['inet', '   '            ]    , AppArmorBug), # whitespace type_or_protocol<br>
+        (['xyxy', 'tcp'            ]    , AppArmorBug), # invalid domain<br>
+        (['inet', 'xyxy'           ]    , AppArmorBug), # invalid type_or_protocol<br>
+        ([dict(), 'tcp'            ]    , AppArmorBug), # wrong type for domain<br>
</div></div>+        ([None  , 'tcp'            ]    , AppArmorBug), # wrong type for domain<br>
<span class="">+        (['inet', dict()           ]    , AppArmorBug), # wrong type for type_or_protocol<br>
</span>+        (['inet', None             ]    , AppArmorBug), # wrong type for type_or_protocol<br>
<div><div class="h5">+        ([NetworkRule.ALL, 'stream']    , AppArmorException), # stream requires a domain<br>
+    ]<br>
+<br>
+    def _run_test(self, params, expected):<br>
+        with self.assertRaises(expected):<br>
+            NetworkRule(params[0], params[1])<br>
+<br>
+    def test_missing_params_1(self):<br>
+        with self.assertRaises(TypeError):<br>
+            NetworkRule()<br>
+<br>
+    def test_missing_params_2(self):<br>
+        with self.assertRaises(TypeError):<br>
+            NetworkRule('inet')<br>
+<br>
+<br>
+class InvalidNetworkTest(AATest):<br>
+    def _check_invalid_rawrule(self, rawrule):<br>
+        obj = None<br>
+        with self.assertRaises(AppArmorException):<br>
+            obj = NetworkRule(NetworkRule.parse(rawrule))<br>
+<br>
+        self.assertIsNone(obj, 'NetworkRule handed back an object unexpectedly')<br>
+<br>
+    def test_invalid_net_missing_comma(self):<br>
+        self._check_invalid_rawrule('network')  # missing comma<br>
+<br>
+    def test_invalid_net_non_NetworkRule(self):<br>
+        self._check_invalid_rawrule('dbus,')  # not a network rule<br>
+<br>
</div></div>+    def test_empty_net_data_1(self):<br>
<div><div class="h5">+        obj = NetworkRule('inet', 'stream')<br>
+        obj.domain = ''<br>
+        # no domain set, and ALL not set<br>
+        with self.assertRaises(AppArmorBug):<br>
+            obj.get_clean(1)<br>
+<br>
+    def test_empty_net_data_2(self):<br>
+        obj = NetworkRule('inet', 'stream')<br>
+        obj.type_or_protocol = ''<br>
+        # no type_or_protocol set, and ALL not set<br>
+        with self.assertRaises(AppArmorBug):<br>
+            obj.get_clean(1)<br>
+<br>
+<br>
+class WriteNetworkTestAATest(AATest):<br>
+    def _run_test(self, rawrule, expected):<br>
+        obj = NetworkRule.parse(rawrule)<br>
+        clean = obj.get_clean()<br>
+        raw = obj.get_raw()<br>
+<br>
+        self.assertEqual(expected.strip(), clean, 'unexpected clean rule')<br>
+        self.assertEqual(rawrule.strip(), raw, 'unexpected raw rule')<br>
+<br>
+    tests = [<br>
+        #  raw rule                                               clean rule<br>
+        ('     network         ,    # foo        '              , 'network, # foo'),<br>
+        ('    audit     network inet,'                          , 'audit network inet,'),<br>
+        ('   deny network         inet      stream,# foo bar'   , 'deny network inet stream, # foo bar'),<br>
+        ('   deny network         inet      ,# foo bar'         , 'deny network inet, # foo bar'),<br>
+        ('   allow network         tcp      ,# foo bar'         , 'allow network tcp, # foo bar'),<br>
+    ]<br>
+<br>
+    def test_write_manually(self):<br>
+        obj = NetworkRule('inet', 'stream', allow_keyword=True)<br>
+<br>
+        expected = '    allow network inet stream,'<br>
+<br>
+        self.assertEqual(expected, obj.get_clean(2), 'unexpected clean rule')<br>
+        self.assertEqual(expected, obj.get_raw(2), 'unexpected raw rule')<br>
</div></div><div><div class="h5">+<br>
+<br>
+class NetworkCoveredTest(AATest):<br>
+    def _run_test(self, param, expected):<br>
+        obj = NetworkRule.parse(self.rule)<br>
+        check_obj = NetworkRule.parse(param)<br>
+<br>
+        self.assertEqual(obj.is_equal(check_obj), expected[0], 'Mismatch in is_equal, expected %s' % expected[0])<br>
+        self.assertEqual(obj.is_equal(check_obj, True), expected[1], 'Mismatch in is_equal/strict, expected %s' % expected[1])<br>
+<br>
+        self.assertEqual(obj.is_covered(check_obj), expected[2], 'Mismatch in is_covered, expected %s' % expected[2])<br>
+        self.assertEqual(obj.is_covered(check_obj, True, True), expected[3], 'Mismatch in is_covered/exact, expected %s' % expected[3])<br>
+<br>
+class NetworkCoveredTest_01(NetworkCoveredTest):<br>
+    rule = 'network inet,'<br>
+<br>
+    tests = [<br>
+        #   rule                                equal     strict equal    covered     covered exact<br>
+        ('network,'                         , [ False   , False         , False     , False     ]),<br>
+        ('network inet,'                    , [ True    , True          , True      , True      ]),<br>
+        ('network inet, # comment'          , [ True    , False         , True      , True      ]),<br>
+        ('allow network inet,'              , [ True    , False         , True      , True      ]),<br>
+        ('network     inet,'                , [ True    , False         , True      , True      ]),<br>
+        ('network inet stream,'             , [ False   , False         , True      , True      ]),<br>
+        ('network inet tcp,'                , [ False   , False         , True      , True      ]),<br>
+        ('audit network inet,'              , [ False   , False         , False     , False     ]),<br>
+        ('audit network,'                   , [ False   , False         , False     , False     ]),<br>
+        ('network unix,'                    , [ False   , False         , False     , False     ]),<br>
+        ('network tcp,'                     , [ False   , False         , False     , False     ]),<br>
+        ('audit deny network inet,'         , [ False   , False         , False     , False     ]),<br>
+        ('deny network inet,'               , [ False   , False         , False     , False     ]),<br>
+    ]<br>
+<br>
+class NetworkCoveredTest_02(NetworkCoveredTest):<br>
+    rule = 'audit network inet,'<br>
+<br>
+    tests = [<br>
+        #   rule                                equal     strict equal    covered     covered exact<br>
+        (      'network inet,'              , [ False   , False         , True      , False     ]),<br>
+        ('audit network inet,'              , [ True    , True          , True      , True      ]),<br>
+        (      'network inet stream,'       , [ False   , False         , True      , False     ]),<br>
+        ('audit network inet stream,'       , [ False   , False         , True      , True      ]),<br>
+        (      'network,'                   , [ False   , False         , False     , False     ]),<br>
+        ('audit network,'                   , [ False   , False         , False     , False     ]),<br>
+        ('network unix,'                    , [ False   , False         , False     , False     ]),<br>
+    ]<br>
+<br>
+<br>
+class NetworkCoveredTest_03(NetworkCoveredTest):<br>
+    rule = 'network inet stream,'<br>
+<br>
+    tests = [<br>
+        #   rule                                equal     strict equal    covered     covered exact<br>
+        (      'network inet stream,'       , [ True    , True          , True      , True      ]),<br>
+        ('allow network inet stream,'       , [ True    , False         , True      , True      ]),<br>
+        (      'network inet,'              , [ False   , False         , False     , False     ]),<br>
+        (      'network,'                   , [ False   , False         , False     , False     ]),<br>
+        (      'network inet tcp,'          , [ False   , False         , False     , False     ]),<br>
+        ('audit network,'                   , [ False   , False         , False     , False     ]),<br>
+        ('audit network inet stream,'       , [ False   , False         , False     , False     ]),<br>
+        (      'network unix,'              , [ False   , False         , False     , False     ]),<br>
+        (      'network,'                   , [ False   , False         , False     , False     ]),<br>
+    ]<br>
+<br>
+class NetworkCoveredTest_04(NetworkCoveredTest):<br>
+    rule = 'network,'<br>
+<br>
+    tests = [<br>
+        #   rule                                equal     strict equal    covered     covered exact<br>
+        (      'network,'                   , [ True    , True          , True      , True      ]),<br>
+        ('allow network,'                   , [ True    , False         , True      , True      ]),<br>
+        (      'network inet,'              , [ False   , False         , True      , True      ]),<br>
+        (      'network inet6 stream,'      , [ False   , False         , True      , True      ]),<br>
+        (      'network tcp,'               , [ False   , False         , True      , True      ]),<br>
+        (      'network inet raw,'          , [ False   , False         , True      , True      ]),<br>
+        ('audit network,'                   , [ False   , False         , False     , False     ]),<br>
+        ('deny  network,'                   , [ False   , False         , False     , False     ]),<br>
+    ]<br>
+<br>
+class NetworkCoveredTest_05(NetworkCoveredTest):<br>
+    rule = 'deny network inet,'<br>
+<br>
+    tests = [<br>
+        #   rule                                equal     strict equal    covered     covered exact<br>
+        (      'deny network inet,'         , [ True    , True          , True      , True      ]),<br>
+        ('audit deny network inet,'         , [ False   , False         , False     , False     ]),<br>
+        (           'network inet,'         , [ False   , False         , False     , False     ]), # XXX should covered be true here?<br>
+        (      'deny network unix,'         , [ False   , False         , False     , False     ]),<br>
+        (      'deny network,'              , [ False   , False         , False     , False     ]),<br>
+    ]<br>
+<br>
+<br>
+class NetworkCoveredTest_Invalid(AATest):<br>
+    def test_borked_obj_is_covered_1(self):<br>
+        obj = NetworkRule.parse('network inet,')<br>
+<br>
+        testobj = NetworkRule('inet', 'stream')<br>
+        testobj.domain = ''<br>
+<br>
+        with self.assertRaises(AppArmorBug):<br>
+            obj.is_covered(testobj)<br>
+<br>
+    def test_borked_obj_is_covered_2(self):<br>
+        obj = NetworkRule.parse('network inet,')<br>
+<br>
+        testobj = NetworkRule('inet', 'stream')<br>
+        testobj.type_or_protocol = ''<br>
+<br>
+        with self.assertRaises(AppArmorBug):<br>
+            obj.is_covered(testobj)<br>
+<br>
+    def test_invalid_is_covered(self):<br>
+        obj = NetworkRule.parse('network inet,')<br>
+<br>
+        testobj = BaseRule()  # different type<br>
+<br>
+        with self.assertRaises(AppArmorBug):<br>
+            obj.is_covered(testobj)<br>
+<br>
+    def test_invalid_is_equal(self):<br>
+        obj = NetworkRule.parse('network inet,')<br>
+<br>
+        testobj = BaseRule()  # different type<br>
+<br>
+        with self.assertRaises(AppArmorBug):<br>
+            obj.is_equal(testobj)<br>
+<br>
+## --- tests for NetworkRuleset --- #<br>
+<br>
+class NetworkRulesTest(AATest):<br>
+    def test_empty_ruleset(self):<br>
+        ruleset = NetworkRuleset()<br>
+        ruleset_2 = NetworkRuleset()<br>
+        self.assertEqual([], ruleset.get_raw(2))<br>
+        self.assertEqual([], ruleset.get_clean(2))<br>
+        self.assertEqual([], ruleset_2.get_raw(2))<br>
+        self.assertEqual([], ruleset_2.get_clean(2))<br>
+<br>
+    def test_ruleset_1(self):<br>
+        ruleset = NetworkRuleset()<br>
+        rules = [<br>
+            'network tcp,',<br>
+            'network inet,',<br>
+        ]<br>
+<br>
+        expected_raw = [<br>
+            'network tcp,',<br>
+            'network inet,',<br>
+            '',<br>
+        ]<br>
+<br>
+        expected_clean = [<br>
+            'network inet,',<br>
+            'network tcp,',<br>
+            '',<br>
+        ]<br>
+<br>
+        for rule in rules:<br>
+            ruleset.add(NetworkRule.parse(rule))<br>
+<br>
+        self.assertEqual(expected_raw, ruleset.get_raw())<br>
+        self.assertEqual(expected_clean, ruleset.get_clean())<br>
+<br>
+    def test_ruleset_2(self):<br>
+        ruleset = NetworkRuleset()<br>
+        rules = [<br>
+            'network inet6 raw,',<br>
+            'allow network inet,',<br>
+            'deny network udp, # example comment',<br>
+        ]<br>
+<br>
+        expected_raw = [<br>
+            '  network inet6 raw,',<br>
+            '  allow network inet,',<br>
+            '  deny network udp, # example comment',<br>
+            '',<br>
+        ]<br>
+<br>
+        expected_clean = [<br>
+            '  deny network udp, # example comment',<br>
+            '',<br>
+            '  allow network inet,',<br>
+            '  network inet6 raw,',<br>
+            '',<br>
+        ]<br>
+<br>
+        for rule in rules:<br>
+            ruleset.add(NetworkRule.parse(rule))<br>
+<br>
+        self.assertEqual(expected_raw, ruleset.get_raw(1))<br>
+        self.assertEqual(expected_clean, ruleset.get_clean(1))<br>
+<br>
+<br>
+class NetworkGlobTestAATest(AATest):<br>
+    def setUp(self):<br>
+        self.maxDiff = None<br>
+        self.ruleset = NetworkRuleset()<br>
+<br>
+    def test_glob_1(self):<br>
+        self.assertEqual(self.ruleset.get_glob('network inet,'), 'network,')<br>
+<br>
+    # not supported or used yet<br>
+    # def test_glob_2(self):<br>
+    #     self.assertEqual(self.ruleset.get_glob('network inet raw,'), 'network inet,')<br>
+<br>
+    def test_glob_ext(self):<br>
+        with self.assertRaises(AppArmorBug):<br>
+            # get_glob_ext is not available for network rules<br>
+            self.ruleset.get_glob_ext('network inet raw,')<br>
+<br>
+class NetworkDeleteTestAATest(AATest):<br>
+    pass<br>
+<br>
+setup_all_loops(__name__)<br>
+if __name__ == '__main__':<br>
+    unittest.main(verbosity=2)<br>
<br>
<br></div></div></blockquote><div>Thank for the patch and follow-up.<br><br>Acked-by: Kshitij Gupta <<a href="mailto:kgupta8592@gmail.com" target="_blank">kgupta8592@gmail.com</a>>.<br><br></div><div>Regards,<br><br></div><div>Kshitij Gupta<br> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div><div class="h5">
<br>
<br>
</div></div>Regards,<br>
<br>
Christian Boltz<br>
<span class=""><font color="#888888">--<br>
[KDE3 vs. KDE4] My guess is the vocal minority will only be satisfied<br>
when KDE4 gets dropped. We need to let them know that might happen<br>
round about the release of KDE5.4 .   [from a comment on<br>
<a href="http://blogs.warwick.ac.uk/bweber/entry/opensuse_110_kde4/" target="_blank">http://blogs.warwick.ac.uk/bweber/entry/opensuse_110_kde4/</a>]<br>
</font></span><div class=""><div class="h5"><br>
<br>
--<br>
AppArmor mailing list<br>
<a href="mailto:AppArmor@lists.ubuntu.com">AppArmor@lists.ubuntu.com</a><br>
Modify settings or unsubscribe at: <a href="https://lists.ubuntu.com/mailman/listinfo/apparmor" target="_blank">https://lists.ubuntu.com/mailman/listinfo/apparmor</a><br>
</div></div></blockquote></div><br></div></div>