#!/usr/bin/python3
# -*- coding: UTF-8 -*-

# ------------------------------------------------------------------
#
#    Copyright (C) 2013-2015 Canonical Ltd.
#
#    This program is free software; you can redistribute it and/or
#    modify it under the terms of version 2 of the GNU General Public
#    License published by the Free Software Foundation.
#
# ------------------------------------------------------------------

# not needed for python3, but pyflakes is grumpy without it
from __future__ import print_function, unicode_literals

from src.apparmor import click
from apparmor.common import AppArmorException
import json
import os
import re
import shutil
import sys
import tempfile
import time
import unittest
from gi.repository import Click

db = Click.DB()
db.read()
click_databases = "{%s}" % ",".join(sorted([db.get(i).props.root for i in
                                            range(db.props.size)]))


class ClickState(object):
    def __init__(self, rootdir):
        self.rootdir = rootdir
        # note: this contains a '_' to trip up the name parsing code
        # if not properly filtered off
        self.click_dir = os.path.join(self.rootdir, "click_apparmor")
        os.mkdir(self.click_dir)
        global click_databases
        self.packages_tree = os.path.join(self.rootdir, "click.ubuntu.com")
        # self.packages_tree = []
        # for d in click_databases:
        #     self.packages_tree.append(self.rootdir + d)
        # for d in self.packages_tree:
        #     os.makedirs(d)
        self.profiles_dir = os.path.join(self.rootdir, "apparmor-profiles")
        os.mkdir(self.profiles_dir)

    def _stub_json(self, name, version):
        j = dict()

        # many tests assume a policy version of 1.0, so use ubuntu-sdk-13.10
        # by default
        j['framework'] = 'ubuntu-sdk-13.10'
        j['name'] = name
        j['version'] = version
        j['hooks'] = dict()
        j['title'] = "Some silly demo app called %s" % (name)
        j['maintainer'] = 'Büggy McJerkerson <buggy@bad.soft.warez>'
        return j

    def _add_app_to_json(self, app, aa_profile=False):
        j = self.manifest_json
        j['hooks'][app] = dict()
        if aa_profile:
            j['hooks'][app]['apparmor-profile'] = "apparmor/%s.profile" % (app)
        else:
            j['hooks'][app]['apparmor'] = "apparmor/%s.json" % (app)
        with open(self.click_manifest, "w", encoding="UTF-8") as f:
            json.dump(j, f, indent=2, separators=(',', ': '), sort_keys=True,
                      ensure_ascii=False)

    def _get_profile(self):
        p = '''# Test package profile
#include <tunables/global>
# Specified profile variables
###VAR###
###PROFILEATTACH### {
  #include <abstractions/base>
  # Read-only for the install directory
  @{CLICK_DIR}/@{APP_PKGNAME}/                   r,
  @{CLICK_DIR}/@{APP_PKGNAME}/@{APP_VERSION}/    r,
  @{CLICK_DIR}/@{APP_PKGNAME}/@{APP_VERSION}/**  mrklix,
}
'''
        return p

    def add_package(self, name, version, framework=None):
        self.package = name
        self.version = version
        self.click_pkgdir = os.path.join(self.packages_tree, name, version,
                                         ".click", "info")
        self.pkg_dir = os.path.join(self.packages_tree, name, version)
        os.makedirs(self.click_pkgdir)
        self.manifest_json = self._stub_json(name, version)
        if framework == "":
            del(self.manifest_json['framework'])
        elif framework:
            self.manifest_json['framework'] = framework
        self.click_manifest = os.path.join(self.click_pkgdir, "%s.manifest" %
                                           (name))
        with open(self.click_manifest, "w+", encoding="UTF-8") as f:
            json.dump(self.manifest_json, f, indent=2, separators=(',', ': '),
                      sort_keys=True, ensure_ascii=False)

    def add_app(self, appname, manifest=None, override=None, additional=None,
                aa_profile=None, fn_type=None):
        os.mkdir(os.path.join(self.click_pkgdir, "apparmor"))
        if aa_profile is None:
            aa_ext = "json"
        else:
            aa_ext = "profile"
        aa_out = os.path.join(self.click_pkgdir, "apparmor", "%s.%s" %
                              (appname, aa_ext))
        self._add_app_to_json(appname, aa_profile)

        with open(aa_out, "w+", encoding="UTF-8") as f:
            if manifest is not None:
                f.write(manifest)
            elif aa_profile is not None:
                f.write(aa_profile)
            f.close()
        aa_out_symfn = os.path.join(self.click_dir,
                                    "%s_%s_%s.%s" % (self.package,
                                                     appname,
                                                     self.version,
                                                     aa_ext))
        os.symlink(aa_out, aa_out_symfn)

        if fn_type == "package":
            aa_json_base = os.path.join(self.click_dir, "%s.%s" %
                                        (self.package, aa_ext))
        elif fn_type == "appname":
            aa_json_base = os.path.join(self.click_dir, "%s_%s.%s" %
                                        (self.package, appname, aa_ext))
        else:
            aa_json_base = aa_out_symfn

        if override is not None and aa_profile is None:
            aa_json_override = "%s.override" % aa_json_base
            with open(aa_json_override, "w+", encoding="UTF-8") as f:
                f.write(override)
                f.close()

        if additional is not None and aa_profile is None:
            aa_json_additional = "%s.additional" % aa_json_base
            with open(aa_json_additional, "w+", encoding="UTF-8") as f:
                f.write(additional)
                f.close()


class T(unittest.TestCase):
    def setUp(self):
        self.tmpdir = tempfile.mkdtemp(prefix="aa-click-manifest-")
        self.clickstate = ClickState(self.tmpdir)
        self.maxDiff = None

    def tearDown(self):
        if os.path.exists(self.tmpdir):
            shutil.rmtree(self.tmpdir)

    def test_click_databases(self):
        '''Test that click databases is not empty'''
        tmp = click_databases.strip('[{}]').split(',')
        self.assertTrue(len(tmp) > 0, "click_databases is empty: '%s'" %
                        click_databases)

    def test_manifest_name_parsing_1(self):
        '''Test simple acceptance for parsing click manifest name'''
        ex_app = "com.ubuntu.developer.username.myapp"
        ex_name = "myapp"
        ex_vers = "0.1"
        fname = "%s_%s_%s.json" % (ex_app, ex_name, ex_vers)

        (app, appname, version) = click.parse_manifest_name(fname)

        self.assertEquals(ex_app, app, "expected app %s, got %s" %
                                       (ex_app, app))
        self.assertEquals(ex_name, appname, "expected appname %s, got %s" %
                                            (ex_name, appname))
        self.assertEquals(ex_vers, version, "expected version %s, got %s" %
                                            (ex_vers, version))

    def test_bad_manifest_name(self):
        '''Test manifest name with not enough elements'''
        ex_app = "com.ubuntu.developer.username.myapp"
        ex_name = "myapp"
        ex_vers = "0.1"
        fname = "%s_%s%s" % (ex_app, ex_name, ex_vers)

        try:
            (app, appname, version) = click.parse_manifest_name(fname)
        except AppArmorException:
            return
        except Exception:
            raise
        raise Exception("name %s should be invalid" % (fname))

    def test_bad_manifest_name_2(self):
        '''Test manifest name with too many elements'''
        ex_app = "com.ubuntu.developer.username.myapp"
        ex_name = "myapp"
        ex_vers = "0.1"
        fname = "%s_%s_%s_err" % (ex_app, ex_name, ex_vers)

        try:
            (app, appname, version) = click.parse_manifest_name(fname)
        except AppArmorException:
            return
        except Exception:
            raise
        raise Exception("name %s should be invalid" % (fname))

    def test_click_name_to_profile(self):
        '''Test click name conversion to profile name'''

        profile = "com.ubuntu.developer.username.myapp_myapp_0.3"
        expected = "%s.json" % (profile)
        orig = "click_%s" % (profile)
        app = click.AppName(profile_filename=orig)
        self.assertEquals(expected, app.click_name,
                          "expected click name %s, got %s" % (expected,
                                                              app.click_name))

    def test_click_appname_no_args_to_init(self):
        '''Test AppName has args'''
        try:
            click.AppName()
        except AppArmorException:
            return
        except Exception:
            raise
        raise Exception("name unset should be invalid")

    def test_click_appname_bad_click_name(self):
        '''Test AppName with bad click_name'''
        n = "bad"
        try:
            click.AppName(click_name="bad")
        except AppArmorException:
            return
        except Exception:
            raise
        raise Exception("click_name '%s' should be invalid" % n)

    def test_click_appname_bad_profile_filename(self):
        '''Test AppName with bad profile_filename'''
        n = "bad"
        try:
            click.AppName(profile_filename="bad")
        except AppArmorException:
            return
        except Exception:
            raise
        raise Exception("profile_filename '%s' should be invalid" % n)

    def test_profile_name_to_click(self):
        '''Test profile name conversion to click name'''

        orig = "com.ubuntu.developer.username.myapp_myapp_0.3.json"
        expected = "click_com.ubuntu.developer.username.myapp_myapp_0.3"
        app = click.AppName(orig)
        self.assertEquals(expected, app.profile_filename,
                          "expected profile filename %s, got %s" %
                          (expected, app.profile_filename))

        expected = "com.ubuntu.developer.username.myapp_myapp_0.3"
        self.assertEquals(expected, app.profile_name,
                          "expected profile name %s, got %s" %
                          (expected, app.profile_name))

    def test_find_manifest_file(self):
        '''Test being given a symlink and finding the main package manifest'''
        c = self.clickstate
        c.add_package("package", "version")
        c.add_app("app")

        (result, pkg_dir) = click.get_package_manifest(
            os.path.join(c.click_dir, "package_app_version.json"), "package")
        self.assertEquals(c.click_manifest, result,
                          "Expected to get %s, got %s" %
                          (c.click_manifest, result))
        self.assertEquals(c.pkg_dir, pkg_dir, "Expected to get %s, got %s" %
                                              (c.pkg_dir, pkg_dir))

    def test_parse_security_manifest(self):
        '''Test being given a symlink and parsing the manifests'''
        c = self.clickstate
        c.add_package("com.ubuntu.developer.username.myapp", "0.1")
        security_json = '''{
  "policy_groups": [ "networking" ],
  "policy_version": 1.0
}'''
        appname = 'sample-app'
        c.add_app(appname, manifest=security_json)

        n = "com.ubuntu.developer.username.myapp_%s_0.1.json" % appname
        nbase = n.strip(".json")
        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        dbus_id = click.dbus_path(nbase)
        dbus_pkgname = click.dbus_path(c.package)

        expected = json.loads('''{
  "profiles": {
    "com.ubuntu.developer.username.myapp_%s_0.1": {
      "policy_groups": [ "networking" ],
      "policy_vendor": "ubuntu",
      "policy_version": 1.0,
      "template": "ubuntu-sdk",
      "template_variables": {
        "APP_ID_DBUS": "%s",
        "APP_PKGNAME_DBUS": "%s",
        "APP_PKGNAME": "com.ubuntu.developer.username.myapp",
        "APP_APPNAME": "%s",
        "APP_VERSION": "0.1",
        "CLICK_DIR": "%s"
      }
    }
  }
}''' % (appname, dbus_id, dbus_pkgname, appname, click_databases))
        self.assertEquals(expected, easyprof_manifest,
                          "Expected to get %s, got %s" %
                          (expected, easyprof_manifest))

        # verify we're testing the json structures deeply
        expected['profiles'][nbase]['template_variables']['BOGUS_VAR'] = \
            'bogus'
        self.assertNotEquals(expected, easyprof_manifest,
                             "Expected %s and %s to differ" %
                             (expected, easyprof_manifest))

    def test_transform_nonexistent_framework(self):
        '''Test transform() with invalid framework'''
        c = self.clickstate
        c.add_package("com.ubuntu.developer.username.myapp", "0.1")
        security_json = '''{
  "policy_groups": [ "networking" ],
  "policy_version": 1.0
}'''
        c.add_app('sample-app', manifest=security_json)

        n = "com.ubuntu.developer.username.myapp_sample-app_0.1.json"
        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        cm.framework = "nonexistent"
        try:
            click.transform(cm)
        except click.AppArmorExceptionClickFrameworkNotFound as e:
            self.assertTrue("Unknown framework" in str(e))
            return
        except Exception:
            raise
        raise Exception("Should have failed on nonexistent framework")

    def test_parse_security_manifest_without_required_field(self):
        '''Test click manifest without required field'''
        j = dict()
        j['version'] = "0.1"
        j['hooks'] = dict()
        j['title'] = "Some silly demo app"
        j['maintainer'] = 'Büggy McJerkerson <buggy@bad.soft.warez>'

        self.click_manifest = os.path.join(self.tmpdir, "test-app.manifest")
        with open(self.click_manifest, "w+", encoding="UTF-8") as f:
            json.dump(j, f, indent=2, separators=(',', ': '), sort_keys=True,
                      ensure_ascii=False)
        try:
            click.read_click_manifest(self.click_manifest)
        except AppArmorException:
            return
        except Exception:
            raise
        raise Exception("Should have errored on missing name")

    # the top level of the security manifest is not *supposed* to
    # be a single dict entry of the app, but apparently this happens.
    # Accept it and move on
    def test_parse_security_manifest_lenient(self):
        '''Test being given a symlink and parsing the manifests, leniently'''
        c = self.clickstate
        c.add_package("com.ubuntu.developer.username.myapp", "0.3")
        security_json = '''{
  "sample-app": {
    "policy_groups": [ "networking" ],
    "policy_version": 1.0
  }
}'''
        appname = 'sample-app'
        c.add_app(appname, manifest=security_json)

        n = "com.ubuntu.developer.username.myapp_%s_0.3.json" % appname
        nbase = n.strip(".json")
        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        dbus_id = click.dbus_path(nbase)
        dbus_pkgname = click.dbus_path(c.package)

        expected = json.loads('''{
  "profiles": {
    "%s": {
      "policy_groups": [ "networking" ],
      "policy_vendor": "ubuntu",
      "policy_version": 1.0,
      "template": "ubuntu-sdk",
      "template_variables": {
        "APP_ID_DBUS": "%s",
        "APP_PKGNAME_DBUS": "%s",
        "APP_PKGNAME": "com.ubuntu.developer.username.myapp",
        "APP_APPNAME": "%s",
        "APP_VERSION": "0.3",
        "CLICK_DIR": "%s"
      }
    }
  }
}''' % (nbase, dbus_id, dbus_pkgname, appname, click_databases))
        self.assertEquals(expected, easyprof_manifest,
                          "Expected to get %s, got %s" %
                          (expected, easyprof_manifest))

    def test_parse_security_manifest_with_framework(self):
        '''Test being given a symlink and parsing the manifests w/framework
           setting'''
        c = self.clickstate
        c.add_package("com.ubuntu.developer.username.myapp", "0.1",
                      framework='ubuntu-sdk-13.10')
        security_json = '''{
  "policy_groups": [ "networking" ],
  "policy_version": 1.0
}'''
        appname = 'sample-app'
        c.add_app(appname, manifest=security_json)

        n = "com.ubuntu.developer.username.myapp_%s_0.1.json" % appname
        nbase = n.strip(".json")
        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        dbus_id = click.dbus_path(nbase)
        dbus_pkgname = click.dbus_path(c.package)

        expected = json.loads('''{
  "profiles": {
    "%s": {
      "policy_groups": [ "networking" ],
      "policy_vendor": "ubuntu",
      "policy_version": 1.0,
      "template": "ubuntu-sdk",
      "template_variables": {
        "APP_ID_DBUS": "%s",
        "APP_PKGNAME_DBUS": "%s",
        "APP_PKGNAME": "com.ubuntu.developer.username.myapp",
        "APP_APPNAME": "%s",
        "APP_VERSION": "0.1",
        "CLICK_DIR": "%s"
      }
    }
  }
}''' % (nbase, dbus_id, dbus_pkgname, appname, click_databases))
        self.assertEquals(expected, easyprof_manifest,
                          "Expected to get %s, got %s" %
                          (expected, easyprof_manifest))

    def test_parse_security_manifest_unknown_framework(self):
        '''Test unknown framework raises exception'''
        c = self.clickstate
        c.add_package("com.ubuntu.developer.username.myapp", "0.1",
                      framework='unknown-sdk-13.10')
        security_json = '''{
  "policy_groups": [ "networking" ],
  "policy_version": 1.0
}'''
        c.add_app('sample-app', manifest=security_json)

        n = "com.ubuntu.developer.username.myapp_sample-app_0.1.json"
        try:
            cm = click.ClickManifest(os.path.join(c.click_dir, n))
            click.transform(cm)
        except AppArmorException:
            return
        except Exception:
            raise
        raise Exception("Framework should be invalid")

    # the security policy is supposed to have a policy_groups entry even
    # if the list inside it is empty. However, I'm seeing click apps
    # without it so we'll accept it and move_on
    def test_parse_security_manifest_no_policy_groups(self):
        '''Test being given a symlink and parsing the manifests, leniently'''
        c = self.clickstate
        package = "com.ubuntu.developer.username.yourapp"
        c.add_package(package, "0.3")
        security_json = '{ "policy_version": 1.0 }'
        appname = 'sample-app'
        c.add_app(appname, manifest=security_json)

        cm = click.ClickManifest(os.path.join(c.click_dir,
                                 "%s_%s_0.3.json" % (package, appname)))
        easyprof_manifest = click.transform(cm)

        dbus_id = click.dbus_path("%s_%s_0.3" % (package, appname))
        dbus_pkgname = click.dbus_path(c.package)

        expected = json.loads('''{
  "profiles": {
    "%s_%s_0.3": {
      "policy_groups": [ ],
      "policy_vendor": "ubuntu",
      "policy_version": 1.0,
      "template": "ubuntu-sdk",
      "template_variables": {
        "APP_ID_DBUS": "%s",
        "APP_PKGNAME_DBUS": "%s",
        "APP_PKGNAME": "%s",
        "APP_APPNAME": "%s",
        "APP_VERSION": "0.3",
        "CLICK_DIR": "%s"
      }
    }
  }
}''' % (package, appname, dbus_id, dbus_pkgname, package, appname,
            click_databases))
        self.assertEquals(expected, easyprof_manifest,
                          "Expected to get %s, got %s" %
                          (expected, easyprof_manifest))

    def test_parse_security_manifest_no_entries(self):
        '''Test being given a symlink and parsing the manifests, no policy
           whatsoever'''
        c = self.clickstate
        package = "com.ubuntu.newbie.username.yourapp"
        c.add_package(package, "0.3")
        security_json = '{ }'
        appname = 'sample-app'
        c.add_app(appname, manifest=security_json)

        cm = click.ClickManifest(os.path.join(c.click_dir,
                                 "%s_%s_0.3.json" % (package, appname)))
        easyprof_manifest = click.transform(cm)

        dbus_id = click.dbus_path("%s_%s_0.3" % (package, appname))
        dbus_pkgname = click.dbus_path(c.package)

        expected = json.loads('''{
  "profiles": {
    "%s_%s_0.3": {
      "policy_groups": [ ],
      "policy_vendor": "ubuntu",
      "policy_version": 1.0,
      "template": "ubuntu-sdk",
      "template_variables": {
        "APP_ID_DBUS": "%s",
        "APP_PKGNAME_DBUS": "%s",
        "APP_PKGNAME": "%s",
        "APP_APPNAME": "%s",
        "APP_VERSION": "0.3",
        "CLICK_DIR": "%s"
      }
    }
  }
}''' % (package, appname, dbus_id, dbus_pkgname, package, appname,
            click_databases))
        self.assertEquals(expected, easyprof_manifest,
                          "Expected to get %s, got %s" % (expected,
                                                          easyprof_manifest))

    def test_parse_security_manifest_unconfined(self):
        '''Test being given a symlink and parsing the manifests for an
           unconfined app'''

        c = self.clickstate
        pkgname = "com.ubuntu.developer.trusteddev.terminal"
        c.add_package(pkgname, "0.99.9~123")
        security_json = '''{
  "template": "unconfined",
  "policy_groups": [ ],
  "policy_version": 1.0
}'''
        appname = '0wnzered'
        c.add_app(appname, manifest=security_json)

        cm = click.ClickManifest(os.path.join(c.click_dir,
                                 "%s_%s_0.99.9~123.json" % (pkgname, appname)))
        easyprof_manifest = click.transform(cm)

        dbus_id = click.dbus_path("%s_%s_0.99.9~123" % (pkgname, appname))
        dbus_pkgname = click.dbus_path(c.package)

        expected = json.loads('''{
  "profiles": {
    "%s_%s_0.99.9~123": {
      "policy_groups": [ ],
      "policy_vendor": "ubuntu",
      "policy_version": 1.0,
      "template": "unconfined",
      "template_variables": {
        "APP_ID_DBUS": "%s",
        "APP_PKGNAME_DBUS": "%s",
        "APP_PKGNAME": "%s",
        "APP_APPNAME": "%s",
        "APP_VERSION": "0.99.9~123",
        "CLICK_DIR": "%s"
      }
    }
  }
}''' % (pkgname, appname, dbus_id, dbus_pkgname, pkgname, appname,
            click_databases))
        self.assertEquals(expected, easyprof_manifest,
                          "Expected to get %s, got %s" % (expected,
                                                          easyprof_manifest))

    def test_parse_security_manifest_alternative_policy_vendor(self):
        '''Test that an alternative vendor is ok'''

        c = self.clickstate
        pkgname = "com.ubuntu.developer.trusteddev.terminal"
        c.add_package(pkgname, "0.99.9~123")
        security_json = '''{
  "template": "unconfined",
  "policy_groups": [ ],
  "policy_version": 1.0,
  "policy_vendor": "somevendor"
}'''
        appname = '0wnzered'
        c.add_app(appname, manifest=security_json)

        cm = click.ClickManifest(os.path.join(c.click_dir,
                                 "%s_%s_0.99.9~123.json" % (pkgname, appname)))
        easyprof_manifest = click.transform(cm)

        dbus_id = click.dbus_path("%s_%s_0.99.9~123" % (pkgname, appname))
        dbus_pkgname = click.dbus_path(c.package)

        expected = json.loads('''{
  "profiles": {
    "%s_%s_0.99.9~123": {
      "policy_groups": [ ],
      "policy_vendor": "somevendor",
      "policy_version": 1.0,
      "template": "unconfined",
      "template_variables": {
        "APP_ID_DBUS": "%s",
        "APP_PKGNAME_DBUS": "%s",
        "APP_PKGNAME": "%s",
        "APP_APPNAME": "%s",
        "APP_VERSION": "0.99.9~123",
        "CLICK_DIR": "%s"
      }
    }
  }
}''' % (pkgname, appname, dbus_id, dbus_pkgname, pkgname, appname,
            click_databases))
        self.assertEquals(expected, easyprof_manifest,
                          "Expected to get %s, got %s" % (expected,
                                                          easyprof_manifest))

    def test_parse_security_manifest_policy_version(self):
        '''Test numeric policy_version'''
        c = self.clickstate
        package = "com.ubuntu.developer.username.yourapp"
        c.add_package(package, "0.3")
        security_json = '''{
  "policy_groups": [ "networking" ],
  "policy_version": 1.0
}'''
        appname = 'sample-app'
        c.add_app(appname, manifest=security_json)

        cm = click.ClickManifest(os.path.join(c.click_dir,
                                 "%s_%s_0.3.json" % (package, appname)))
        easyprof_manifest = click.transform(cm)

        dbus_id = click.dbus_path("%s_%s_0.3" % (package, appname))
        dbus_pkgname = click.dbus_path(c.package)

        expected = json.loads('''{
  "profiles": {
    "%s_%s_0.3": {
      "policy_groups": [
        "networking"
      ],
      "policy_vendor": "ubuntu",
      "policy_version": 1.0,
      "template": "ubuntu-sdk",
      "template_variables": {
        "APP_ID_DBUS": "%s",
        "APP_PKGNAME_DBUS": "%s",
        "APP_PKGNAME": "%s",
        "APP_APPNAME": "%s",
        "APP_VERSION": "0.3",
        "CLICK_DIR": "%s"
      }
    }
  }
}''' % (package, appname, dbus_id, dbus_pkgname, package, appname,
            click_databases))
        self.assertEquals(expected, easyprof_manifest,
                          "Expected to get %s, got %s" %
                          (expected, easyprof_manifest))

    def test_parse_security_manifest_policy_version_invalid(self):
        '''Test numeric policy_version'''
        c = self.clickstate
        package = "com.ubuntu.developer.username.yourapp"
        c.add_package(package, "0.3")
        security_json = '''{
  "policy_groups": [ "networking" ],
  "policy_version": 0.1
}'''
        c.add_app('sample-app', manifest=security_json)

        cm = click.ClickManifest(os.path.join(c.click_dir,
                                 "%s_sample-app_0.3.json" % package))
        try:
            click.transform(cm)
        except click.AppArmorExceptionClickInvalidPolicyVersion as e:
            self.assertTrue("Invalid policy version" in str(e))
            return
        except Exception:
            raise
        raise Exception("Should have failed on invalid policy_version")

    def test_parse_security_manifest_policy_version_high(self):
        '''Test policy_version high'''
        c = self.clickstate
        package = "com.ubuntu.developer.username.yourapp"
        c.add_package(package, "0.3", framework='ubuntu-sdk-13.10')
        security_json = '''{
  "policy_groups": [ "networking" ],
  "policy_version": 1.1
}'''
        c.add_app('sample-app', manifest=security_json)

        cm = click.ClickManifest(os.path.join(c.click_dir,
                                 "%s_sample-app_0.3.json" % package))
        try:
            click.transform(cm)
        except click.AppArmorExceptionClickInvalidPolicyVersion as e:
            self.assertTrue("Invalid policy version" in str(e))
            return
        except Exception:
            raise
        raise Exception("Should have failed on invalid policy_version")

    def test_parse_security_manifest_policy_version_low(self):
        '''Test policy_version low'''
        c = self.clickstate
        package = "com.ubuntu.developer.username.yourapp"
        c.add_package(package, "0.3", framework='ubuntu-sdk-14.04')
        security_json = '''{
  "policy_groups": [ "networking" ],
  "policy_version": 1.0
}'''
        c.add_app('sample-app', manifest=security_json)

        cm = click.ClickManifest(os.path.join(c.click_dir,
                                 "%s_sample-app_0.3.json" % package))
        try:
            click.transform(cm)
        except click.AppArmorExceptionClickInvalidPolicyVersion as e:
            self.assertTrue("Invalid policy version" in str(e))
            return
        except Exception:
            raise
        raise Exception("Should have failed on invalid policy_version")

    def test_parse_security_manifest_policy_version_without_decimal(self):
        '''Test numeric policy_version without decimal (LP: #1214618)'''
        c = self.clickstate
        package = "com.ubuntu.developer.username.yourapp"
        c.add_package(package, "0.3")
        security_json = '''{
  "policy_groups": [ "networking" ],
  "policy_version": 1
}'''
        appname = 'sample-app'
        c.add_app(appname, manifest=security_json)

        cm = click.ClickManifest(os.path.join(c.click_dir,
                                 "%s_%s_0.3.json" % (package, appname)))
        easyprof_manifest = click.transform(cm)

        dbus_id = click.dbus_path("%s_%s_0.3" % (package, appname))
        dbus_pkgname = click.dbus_path(c.package)

        expected = json.loads('''{
  "profiles": {
    "%s_%s_0.3": {
      "policy_groups": [
        "networking"
      ],
      "policy_vendor": "ubuntu",
      "policy_version": 1.0,
      "template": "ubuntu-sdk",
      "template_variables": {
        "APP_ID_DBUS": "%s",
        "APP_PKGNAME_DBUS": "%s",
        "APP_PKGNAME": "%s",
        "APP_APPNAME": "%s",
        "APP_VERSION": "0.3",
        "CLICK_DIR": "%s"
      }
    }
  }
}''' % (package, appname, dbus_id, dbus_pkgname, package, appname,
            click_databases))
        self.assertEquals(expected, easyprof_manifest,
                          "Expected to get %s, got %s" %
                          (expected, easyprof_manifest))

    # The security policy is supposed to have a JSON Number. The click hook
    # currently will convert "1.0" to 1.0 for easyprof. Test for that.
    def test_parse_security_manifest_policy_version_as_string(self):
        '''Test numeric policy_version as string'''
        c = self.clickstate
        package = "com.ubuntu.developer.username.yourapp"
        c.add_package(package, "0.3")
        security_json = '''{
  "policy_groups": [ "networking" ],
  "policy_version": "1.0"
}'''
        appname = 'sample-app'
        c.add_app(appname, manifest=security_json)

        cm = click.ClickManifest(os.path.join(c.click_dir,
                                 "%s_%s_0.3.json" % (package, appname)))
        easyprof_manifest = click.transform(cm)

        dbus_id = click.dbus_path("%s_%s_0.3" % (package, appname))
        dbus_pkgname = click.dbus_path(c.package)

        expected = json.loads('''{
  "profiles": {
    "%s_%s_0.3": {
      "policy_groups": [
        "networking"
      ],
      "policy_vendor": "ubuntu",
      "policy_version": 1.0,
      "template": "ubuntu-sdk",
      "template_variables": {
        "APP_ID_DBUS": "%s",
        "APP_PKGNAME_DBUS": "%s",
        "APP_PKGNAME": "%s",
        "APP_APPNAME": "%s",
        "APP_VERSION": "0.3",
        "CLICK_DIR": "%s"
      }
    }
  }
}''' % (package, appname, dbus_id, dbus_pkgname, package, appname,
            click_databases))
        self.assertEquals(expected, easyprof_manifest,
                          "Expected to get %s, got %s" %
                          (expected, easyprof_manifest))

    # The security policy is supposed to have a JSON Number
    def test_parse_security_manifest_policy_version_is_number(self):
        '''Test numeric policy_version requires a number'''
        c = self.clickstate
        package = "com.ubuntu.developer.username.yourapp"
        c.add_package(package, "0.3")
        v = "abc"
        security_json = '''{
  "policy_groups": [ "networking" ],
  "policy_version": "%s"
}''' % v
        c.add_app('sample-app', manifest=security_json)

        cm = click.ClickManifest(os.path.join(c.click_dir,
                                 "%s_sample-app_0.3.json" % package))
        try:
            click.transform(cm)
        except ValueError:
            return
        except Exception:
            raise
        raise Exception("version %s should be invalid" % (v))

    def test_parse_security_manifest_framework_missing(self):
        '''Test manifest framework (missing)'''
        c = self.clickstate
        package = "com.ubuntu.developer.username.yourapp"
        c.add_package(package, "0.3", framework="")
        security_json = '''{
  "policy_groups": [ "networking" ],
  "policy_version": 1.0
}'''
        appname = 'sample-app'
        c.add_app(appname, manifest=security_json)

        try:
            click.ClickManifest(os.path.join(c.click_dir,
                                "%s_%s_0.3.json" % (package, appname)))
        except click.AppArmorException as e:
            self.assertTrue("could not find required field 'framework' in json"
                            in str(e))
            return
        except Exception:
            raise
        raise Exception("Should have failed on missing framework")

    def test_parse_security_manifest_framework_1310(self):
        '''Test manifest framework (13.10)'''
        c = self.clickstate
        package = "com.ubuntu.developer.username.yourapp"
        c.add_package(package, "0.3", framework='ubuntu-sdk-13.10')
        security_json = '''{
  "policy_groups": [ "networking" ],
  "policy_version": 1.0
}'''
        appname = 'sample-app'
        c.add_app(appname, manifest=security_json)

        cm = click.ClickManifest(os.path.join(c.click_dir,
                                 "%s_%s_0.3.json" % (package, appname)))
        easyprof_manifest = click.transform(cm)

        dbus_id = click.dbus_path("%s_%s_0.3" % (package, appname))
        dbus_pkgname = click.dbus_path(c.package)

        expected = json.loads('''{
  "profiles": {
    "%s_%s_0.3": {
      "policy_groups": [
        "networking"
      ],
      "policy_vendor": "ubuntu",
      "policy_version": 1.0,
      "template": "ubuntu-sdk",
      "template_variables": {
        "APP_ID_DBUS": "%s",
        "APP_PKGNAME_DBUS": "%s",
        "APP_PKGNAME": "%s",
        "APP_APPNAME": "%s",
        "APP_VERSION": "0.3",
        "CLICK_DIR": "%s"
      }
    }
  }
}''' % (package, appname, dbus_id, dbus_pkgname, package, appname,
            click_databases))
        self.assertEquals(expected, easyprof_manifest,
                          "Expected to get %s, got %s" %
                          (expected, easyprof_manifest))

    def test_parse_security_manifest_framework_1404(self):
        '''Test manifest framework (14.04)'''
        c = self.clickstate
        package = "com.ubuntu.developer.username.yourapp"
        c.add_package(package, "0.3", framework='ubuntu-sdk-14.04')
        security_json = '''{
  "policy_groups": [ "networking" ],
  "policy_version": 1.1
}'''
        appname = 'sample-app'
        c.add_app(appname, manifest=security_json)

        cm = click.ClickManifest(os.path.join(c.click_dir,
                                 "%s_%s_0.3.json" % (package, appname)))
        easyprof_manifest = click.transform(cm)

        dbus_id = click.dbus_path("%s_%s_0.3" % (package, appname))
        dbus_pkgname = click.dbus_path(c.package)

        expected = json.loads('''{
  "profiles": {
    "%s_%s_0.3": {
      "policy_groups": [
        "networking"
      ],
      "policy_vendor": "ubuntu",
      "policy_version": 1.1,
      "template": "ubuntu-sdk",
      "template_variables": {
        "APP_ID_DBUS": "%s",
        "APP_PKGNAME_DBUS": "%s",
        "APP_PKGNAME": "%s",
        "APP_APPNAME": "%s",
        "APP_VERSION": "0.3",
        "CLICK_DIR": "%s"
      }
    }
  }
}''' % (package, appname, dbus_id, dbus_pkgname, package, appname,
            click_databases))
        self.assertEquals(expected, easyprof_manifest,
                          "Expected to get %s, got %s" %
                          (expected, easyprof_manifest))

    def test_parse_security_manifest_framework_1404_subframework(self):
        '''Test manifest framework 14.04 (subframeworks)'''
        for sub in ['-dev', '-dev1',
                    '-html-dev1', '-html',
                    '-papi-dev2', '-papi',
                    '-qml-dev3', 'qml']:
            c = self.clickstate
            package = "com.ubuntu.developer.username.yourapp%s" % sub
            c.add_package(package, "0.3",
                          framework='ubuntu-sdk-14.04%s' % sub)
            security_json = '''{
  "policy_groups": [ "networking" ],
  "policy_version": 1.1
}'''
            appname = 'sample-app'
            c.add_app(appname, manifest=security_json)

            cm = click.ClickManifest(os.path.join(c.click_dir,
                                     "%s_%s_0.3.json" % (package, appname)))
            easyprof_manifest = click.transform(cm)

            dbus_id = click.dbus_path("%s_%s_0.3" % (package, appname))
            dbus_pkgname = click.dbus_path(c.package)

            expected = json.loads('''{
  "profiles": {
    "%s_%s_0.3": {
      "policy_groups": [
        "networking"
      ],
      "policy_vendor": "ubuntu",
      "policy_version": 1.1,
      "template": "ubuntu-sdk",
      "template_variables": {
        "APP_ID_DBUS": "%s",
        "APP_PKGNAME_DBUS": "%s",
        "APP_PKGNAME": "%s",
        "APP_APPNAME": "%s",
        "APP_VERSION": "0.3",
        "CLICK_DIR": "%s"
      }
    }
  }
}''' % (package, appname, dbus_id, dbus_pkgname, package, appname,
                click_databases))
            self.assertEquals(expected, easyprof_manifest,
                              "Expected to get %s, got %s" %
                              (expected, easyprof_manifest))

    def test_parse_security_manifest_framework_1404_subframework_low(self):
        '''Test manifest framework 14.04 (subframework policy version low)'''
        c = self.clickstate
        package = "com.ubuntu.developer.username.yourapp"
        c.add_package(package, "0.3", framework='ubuntu-sdk-14.04-html')
        security_json = '''{
  "policy_groups": [ "networking" ],
  "policy_version": 1.0
}'''
        c.add_app('sample-app', manifest=security_json)

        cm = click.ClickManifest(os.path.join(c.click_dir,
                                 "%s_sample-app_0.3.json" % package))
        try:
            click.transform(cm)
        except click.AppArmorExceptionClickInvalidPolicyVersion as e:
            self.assertTrue("Invalid policy version" in str(e))
            return
        except Exception:
            raise
        raise Exception("Should have failed on invalid policy_version")

    def test_parse_security_manifest_framework_1410(self):
        '''Test manifest framework (14.10)'''
        c = self.clickstate
        package = "com.ubuntu.developer.username.yourapp"
        c.add_package(package, "0.3", framework='ubuntu-sdk-14.10')
        security_json = '''{
  "policy_groups": [ "networking" ],
  "policy_version": 1.2
}'''
        appname = 'sample-app'
        c.add_app(appname, manifest=security_json)

        cm = click.ClickManifest(os.path.join(c.click_dir,
                                 "%s_%s_0.3.json" % (package, appname)))
        easyprof_manifest = click.transform(cm)

        dbus_id = click.dbus_path("%s_%s_0.3" % (package, appname))
        dbus_pkgname = click.dbus_path(c.package)

        expected = json.loads('''{
  "profiles": {
    "%s_%s_0.3": {
      "policy_groups": [
        "networking"
      ],
      "policy_vendor": "ubuntu",
      "policy_version": 1.2,
      "template": "ubuntu-sdk",
      "template_variables": {
        "APP_ID_DBUS": "%s",
        "APP_PKGNAME_DBUS": "%s",
        "APP_PKGNAME": "%s",
        "APP_APPNAME": "%s",
        "APP_VERSION": "0.3",
        "CLICK_DIR": "%s"
      }
    }
  }
}''' % (package, appname, dbus_id, dbus_pkgname, package, appname,
            click_databases))
        self.assertEquals(expected, easyprof_manifest,
                          "Expected to get %s, got %s" %
                          (expected, easyprof_manifest))

    def test_parse_security_manifest_framework_1410_subframework(self):
        '''Test manifest framework 14.10 (subframeworks)'''
        for sub in ['-dev', '-dev1',
                    '-html-dev1', '-html',
                    '-papi-dev2', '-papi',
                    '-qml-dev3', 'qml']:
            c = self.clickstate
            package = "com.ubuntu.developer.username.yourapp%s" % sub
            c.add_package(package, "0.3",
                          framework='ubuntu-sdk-14.10%s' % sub)
            security_json = '''{
  "policy_groups": [ "networking" ],
  "policy_version": 1.2
}'''
            appname = 'sample-app'
            c.add_app(appname, manifest=security_json)

            cm = click.ClickManifest(os.path.join(c.click_dir,
                                     "%s_%s_0.3.json" % (package, appname)))
            easyprof_manifest = click.transform(cm)

            dbus_id = click.dbus_path("%s_%s_0.3" % (package, appname))
            dbus_pkgname = click.dbus_path(c.package)

            expected = json.loads('''{
  "profiles": {
    "%s_%s_0.3": {
      "policy_groups": [
        "networking"
      ],
      "policy_vendor": "ubuntu",
      "policy_version": 1.2,
      "template": "ubuntu-sdk",
      "template_variables": {
        "APP_ID_DBUS": "%s",
        "APP_PKGNAME_DBUS": "%s",
        "APP_PKGNAME": "%s",
        "APP_APPNAME": "%s",
        "APP_VERSION": "0.3",
        "CLICK_DIR": "%s"
      }
    }
  }
}''' % (package, appname, dbus_id, dbus_pkgname, package, appname,
                click_databases))
            self.assertEquals(expected, easyprof_manifest,
                              "Expected to get %s, got %s" %
                              (expected, easyprof_manifest))

    def test_parse_security_manifest_framework_1504(self):
        '''Test manifest framework (15.04)'''
        c = self.clickstate
        package = "com.ubuntu.developer.username.yourapp"
        c.add_package(package, "0.3", framework='ubuntu-sdk-15.04')
        security_json = '''{
  "policy_groups": [ "networking" ],
  "policy_version": 1.3
}'''
        appname = 'sample-app'
        c.add_app(appname, manifest=security_json)

        cm = click.ClickManifest(os.path.join(c.click_dir,
                                 "%s_%s_0.3.json" % (package, appname)))
        easyprof_manifest = click.transform(cm)

        dbus_id = click.dbus_path("%s_%s_0.3" % (package, appname))
        dbus_pkgname = click.dbus_path(c.package)

        expected = json.loads('''{
  "profiles": {
    "%s_%s_0.3": {
      "policy_groups": [
        "networking"
      ],
      "policy_vendor": "ubuntu",
      "policy_version": 1.3,
      "template": "ubuntu-sdk",
      "template_variables": {
        "APP_ID_DBUS": "%s",
        "APP_PKGNAME_DBUS": "%s",
        "APP_PKGNAME": "%s",
        "APP_APPNAME": "%s",
        "APP_VERSION": "0.3",
        "CLICK_DIR": "%s"
      }
    }
  }
}''' % (package, appname, dbus_id, dbus_pkgname, package, appname,
            click_databases))
        self.assertEquals(expected, easyprof_manifest,
                          "Expected to get %s, got %s" %
                          (expected, easyprof_manifest))

    def test_parse_security_manifest_framework_1504_subframework(self):
        '''Test manifest framework 15.04 (subframeworks)'''
        for sub in ['-dev', '-dev1',
                    '-html-dev1', '-html',
                    '-papi-dev2', '-papi',
                    '-qml-dev3', 'qml']:
            c = self.clickstate
            package = "com.ubuntu.developer.username.yourapp%s" % sub
            c.add_package(package, "0.3",
                          framework='ubuntu-sdk-15.04%s' % sub)
            security_json = '''{
  "policy_groups": [ "networking" ],
  "policy_version": 1.3
}'''
            appname = 'sample-app'
            c.add_app(appname, manifest=security_json)

            cm = click.ClickManifest(os.path.join(c.click_dir,
                                     "%s_%s_0.3.json" % (package, appname)))
            easyprof_manifest = click.transform(cm)

            dbus_id = click.dbus_path("%s_%s_0.3" % (package, appname))
            dbus_pkgname = click.dbus_path(c.package)

            expected = json.loads('''{
  "profiles": {
    "%s_%s_0.3": {
      "policy_groups": [
        "networking"
      ],
      "policy_vendor": "ubuntu",
      "policy_version": 1.3,
      "template": "ubuntu-sdk",
      "template_variables": {
        "APP_ID_DBUS": "%s",
        "APP_PKGNAME_DBUS": "%s",
        "APP_PKGNAME": "%s",
        "APP_APPNAME": "%s",
        "APP_VERSION": "0.3",
        "CLICK_DIR": "%s"
      }
    }
  }
}''' % (package, appname, dbus_id, dbus_pkgname, package, appname,
                click_databases))
            self.assertEquals(expected, easyprof_manifest,
                              "Expected to get %s, got %s" %
                              (expected, easyprof_manifest))

    def test_parse_security_manifest_framework_core_1504(self):
        '''Test manifest framework (core 15.04)'''
        c = self.clickstate
        package = "com.ubuntu.developer.username.yourapp"
        c.add_package(package, "0.3", framework='ubuntu-core-15.04')
        security_json = '''{
  "policy_vendor": "ubuntu-core",
  "template": "service",
  "policy_groups": [ "networking" ],
  "policy_version": 15.04
}'''
        appname = 'sample-app'
        c.add_app(appname, manifest=security_json)

        cm = click.ClickManifest(os.path.join(c.click_dir,
                                 "%s_%s_0.3.json" % (package, appname)))
        easyprof_manifest = click.transform(cm)

        dbus_id = click.dbus_path("%s_%s_0.3" % (package, appname))
        dbus_pkgname = click.dbus_path(c.package)

        expected = json.loads('''{
  "profiles": {
    "%s_%s_0.3": {
      "policy_groups": [
        "networking"
      ],
      "policy_vendor": "ubuntu-core",
      "policy_version": 15.04,
      "template": "service",
      "template_variables": {
        "APP_ID_DBUS": "%s",
        "APP_PKGNAME_DBUS": "%s",
        "APP_PKGNAME": "%s",
        "APP_APPNAME": "%s",
        "APP_VERSION": "0.3",
        "CLICK_DIR": "%s"
      }
    }
  }
}''' % (package, appname, dbus_id, dbus_pkgname, package, appname,
            click_databases))
        self.assertEquals(expected, easyprof_manifest,
                          "Expected to get %s, got %s" %
                          (expected, easyprof_manifest))

    def test_parse_security_manifest_framework_core_1504_list(self):
        '''Test manifest framework (core 15.04) - list'''
        c = self.clickstate
        package = "com.ubuntu.developer.username.yourapp"
        c.add_package(package, "0.3", framework='nonexist,ubuntu-core-15.04')
        security_json = '''{
  "policy_vendor": "ubuntu-core",
  "template": "service",
  "policy_groups": [ "networking" ],
  "policy_version": 15.04
}'''
        appname = 'sample-app'
        c.add_app(appname, manifest=security_json)

        cm = click.ClickManifest(os.path.join(c.click_dir,
                                 "%s_%s_0.3.json" % (package, appname)))
        easyprof_manifest = click.transform(cm)

        dbus_id = click.dbus_path("%s_%s_0.3" % (package, appname))
        dbus_pkgname = click.dbus_path(c.package)

        expected = json.loads('''{
  "profiles": {
    "%s_%s_0.3": {
      "policy_groups": [
        "networking"
      ],
      "policy_vendor": "ubuntu-core",
      "policy_version": 15.04,
      "template": "service",
      "template_variables": {
        "APP_ID_DBUS": "%s",
        "APP_PKGNAME_DBUS": "%s",
        "APP_PKGNAME": "%s",
        "APP_APPNAME": "%s",
        "APP_VERSION": "0.3",
        "CLICK_DIR": "%s"
      }
    }
  }
}''' % (package, appname, dbus_id, dbus_pkgname, package, appname,
            click_databases))
        self.assertEquals(expected, easyprof_manifest,
                          "Expected to get %s, got %s" %
                          (expected, easyprof_manifest))

    def test_parse_security_manifest_framework_core_1504_list2(self):
        '''Test manifest framework (core 15.04) - list altered order'''
        c = self.clickstate
        package = "com.ubuntu.developer.username.yourapp"
        c.add_package(package, "0.3", framework='ubuntu-core-15.04,nonexist')
        security_json = '''{
  "policy_vendor": "ubuntu-core",
  "template": "service",
  "policy_groups": [ "networking" ],
  "policy_version": 15.04
}'''
        appname = 'sample-app'
        c.add_app(appname, manifest=security_json)

        cm = click.ClickManifest(os.path.join(c.click_dir,
                                 "%s_%s_0.3.json" % (package, appname)))
        easyprof_manifest = click.transform(cm)

        dbus_id = click.dbus_path("%s_%s_0.3" % (package, appname))
        dbus_pkgname = click.dbus_path(c.package)

        expected = json.loads('''{
  "profiles": {
    "%s_%s_0.3": {
      "policy_groups": [
        "networking"
      ],
      "policy_vendor": "ubuntu-core",
      "policy_version": 15.04,
      "template": "service",
      "template_variables": {
        "APP_ID_DBUS": "%s",
        "APP_PKGNAME_DBUS": "%s",
        "APP_PKGNAME": "%s",
        "APP_APPNAME": "%s",
        "APP_VERSION": "0.3",
        "CLICK_DIR": "%s"
      }
    }
  }
}''' % (package, appname, dbus_id, dbus_pkgname, package, appname,
            click_databases))
        self.assertEquals(expected, easyprof_manifest,
                          "Expected to get %s, got %s" %
                          (expected, easyprof_manifest))

    def test_parse_security_manifest_framework_core_1504_subframework(self):
        '''Test manifest framework 15.04 core (subframeworks)'''
        for sub in ['-dev', '-dev1']:
            c = self.clickstate
            package = "com.ubuntu.developer.username.yourapp%s" % sub
            c.add_package(package, "0.3",
                          framework='ubuntu-core-15.04%s' % sub)
            security_json = '''{
  "policy_vendor": "ubuntu-core",
  "template": "service",
  "policy_groups": [ "networking" ],
  "policy_version": 15.04
}'''
            appname = 'sample-app'
            c.add_app(appname, manifest=security_json)

            cm = click.ClickManifest(os.path.join(c.click_dir,
                                     "%s_%s_0.3.json" % (package, appname)))
            easyprof_manifest = click.transform(cm)

            dbus_id = click.dbus_path("%s_%s_0.3" % (package, appname))
            dbus_pkgname = click.dbus_path(c.package)

            expected = json.loads('''{
  "profiles": {
    "%s_%s_0.3": {
      "policy_groups": [
        "networking"
      ],
      "policy_vendor": "ubuntu-core",
      "policy_version": 15.04,
      "template": "service",
      "template_variables": {
        "APP_ID_DBUS": "%s",
        "APP_PKGNAME_DBUS": "%s",
        "APP_PKGNAME": "%s",
        "APP_APPNAME": "%s",
        "APP_VERSION": "0.3",
        "CLICK_DIR": "%s"
      }
    }
  }
}''' % (package, appname, dbus_id, dbus_pkgname, package, appname,
                click_databases))
            self.assertEquals(expected, easyprof_manifest,
                              "Expected to get %s, got %s" %
                              (expected, easyprof_manifest))

    def test_parse_security_manifest_framework_core_1504_compat(self):
        '''Test manifest framework (core 15.04) - compat ubuntu-snappy/1.3'''
        c = self.clickstate
        package = "com.ubuntu.developer.username.yourapp"
        c.add_package(package, "0.3", framework='ubuntu-core-15.04')
        security_json = '''{
  "policy_vendor": "ubuntu-snappy",
  "template": "service",
  "policy_groups": [ "networking" ],
  "policy_version": 1.3
}'''
        appname = 'sample-app'
        c.add_app(appname, manifest=security_json)

        cm = click.ClickManifest(os.path.join(c.click_dir,
                                 "%s_%s_0.3.json" % (package, appname)))
        easyprof_manifest = click.transform(cm)

        dbus_id = click.dbus_path("%s_%s_0.3" % (package, appname))
        dbus_pkgname = click.dbus_path(c.package)

        expected = json.loads('''{
  "profiles": {
    "%s_%s_0.3": {
      "policy_groups": [
        "networking"
      ],
      "policy_vendor": "ubuntu-snappy",
      "policy_version": 1.3,
      "template": "service",
      "template_variables": {
        "APP_ID_DBUS": "%s",
        "APP_PKGNAME_DBUS": "%s",
        "APP_PKGNAME": "%s",
        "APP_APPNAME": "%s",
        "APP_VERSION": "0.3",
        "CLICK_DIR": "%s"
      }
    }
  }
}''' % (package, appname, dbus_id, dbus_pkgname, package, appname,
            click_databases))
        self.assertEquals(expected, easyprof_manifest,
                          "Expected to get %s, got %s" %
                          (expected, easyprof_manifest))

    def test_parse_security_manifest_framework_nonexistent(self):
        '''Test framework (nonexistent)'''
        c = self.clickstate
        pkg = "com.ubuntu.developer.username.yourapp"
        c.add_package(pkg, "0.3", framework='nonexistent')
        security_json = '''{
  "policy_groups": [ "networking" ],
  "policy_version": 1.0
}'''
        c.add_app('sample-app', manifest=security_json)

        try:
            cm = click.ClickManifest(os.path.join(c.click_dir,
                                     "%s_sample-app_0.3.json" % pkg))
            click.transform(cm)
        except click.AppArmorExceptionClickFrameworkNotFound as e:
            self.assertTrue("Could not find usable framework in" in str(e))
            return
        except Exception:
            raise
        raise Exception("Should have failed on nonexistent framework")

    def test_parse_security_manifest_abstractions(self):
        '''Test we pass along abstractions to easyprof'''

        c = self.clickstate
        pkgname = "com.ubuntu.developer.trusteddev.terminal"
        c.add_package(pkgname, "0.99.9~123")
        security_json = '''{
  "template": "ubuntu-sdk",
  "policy_groups": [ ],
  "policy_version": 1.0,
  "abstractions": [
    "gnupg",
    "ssl_keys"
  ]
}'''
        appname = '0wnzered'
        c.add_app(appname, manifest=security_json)

        cm = click.ClickManifest(os.path.join(c.click_dir,
                                 "%s_%s_0.99.9~123.json" % (pkgname, appname)))
        easyprof_manifest = click.transform(cm)

        dbus_id = click.dbus_path("%s_%s_0.99.9~123" % (pkgname, appname))
        dbus_pkgname = click.dbus_path(c.package)

        expected = json.loads('''{
  "profiles": {
    "%s_%s_0.99.9~123": {
      "abstractions": [ "gnupg", "ssl_keys" ],
      "policy_groups": [ ],
      "policy_vendor": "ubuntu",
      "policy_version": 1.0,
      "template": "ubuntu-sdk",
      "template_variables": {
        "APP_ID_DBUS": "%s",
        "APP_PKGNAME_DBUS": "%s",
        "APP_PKGNAME": "%s",
        "APP_APPNAME": "%s",
        "APP_VERSION": "0.99.9~123",
        "CLICK_DIR": "%s"
      }
    }
  }
}''' % (pkgname, appname, dbus_id, dbus_pkgname, pkgname, appname,
            click_databases))
        self.assertEquals(expected, easyprof_manifest,
                          "Expected to get %s, got %s" % (expected,
                                                          easyprof_manifest))

    def test_parse_security_manifest_read_paths(self):
        '''Test we pass along read_paths to easyprof'''

        c = self.clickstate
        pkgname = "com.ubuntu.developer.trusteddev.terminal"
        c.add_package(pkgname, "0.99.9~123")
        security_json = '''{
  "template": "ubuntu-sdk",
  "policy_groups": [ ],
  "policy_version": 1.0,
  "read_path": [
    "/tmp/foo_r",
    "/tmp/bar_r/"
  ]
}'''
        appname = '0wnzered'
        c.add_app(appname, manifest=security_json)

        cm = click.ClickManifest(os.path.join(c.click_dir,
                                 "%s_%s_0.99.9~123.json" % (pkgname, appname)))
        easyprof_manifest = click.transform(cm)

        dbus_id = click.dbus_path("%s_%s_0.99.9~123" % (pkgname, appname))
        dbus_pkgname = click.dbus_path(c.package)

        expected = json.loads('''{
  "profiles": {
    "%s_%s_0.99.9~123": {
      "policy_groups": [ ],
      "policy_vendor": "ubuntu",
      "policy_version": 1.0,
      "read_path": [
        "/tmp/foo_r",
        "/tmp/bar_r/"
      ],
      "template": "ubuntu-sdk",
      "template_variables": {
        "APP_ID_DBUS": "%s",
        "APP_PKGNAME_DBUS": "%s",
        "APP_PKGNAME": "%s",
        "APP_APPNAME": "%s",
        "APP_VERSION": "0.99.9~123",
        "CLICK_DIR": "%s"
      }
    }
  }
}''' % (pkgname, appname, dbus_id, dbus_pkgname, pkgname, appname,
            click_databases))
        self.assertEquals(expected, easyprof_manifest,
                          "Expected to get %s, got %s" % (expected,
                                                          easyprof_manifest))

    def test_parse_security_manifest_write_paths(self):
        '''Test we pass along write_paths to easyprof'''

        c = self.clickstate
        pkgname = "com.ubuntu.developer.trusteddev.terminal"
        c.add_package(pkgname, "0.99.9~123")
        security_json = '''{
  "template": "ubuntu-sdk",
  "policy_groups": [ ],
  "policy_version": 1.0,
  "write_path": [
    "/tmp/foo_w",
    "/tmp/bar_w/"
  ]
}'''
        appname = '0wnzered'
        c.add_app(appname, manifest=security_json)

        cm = click.ClickManifest(os.path.join(c.click_dir,
                                 "%s_%s_0.99.9~123.json" % (pkgname, appname)))
        easyprof_manifest = click.transform(cm)

        dbus_id = click.dbus_path("%s_%s_0.99.9~123" % (pkgname, appname))
        dbus_pkgname = click.dbus_path(c.package)

        expected = json.loads('''{
  "profiles": {
    "%s_%s_0.99.9~123": {
      "policy_groups": [ ],
      "policy_vendor": "ubuntu",
      "policy_version": 1.0,
      "write_path": [
        "/tmp/foo_w",
        "/tmp/bar_w/"
      ],
      "template": "ubuntu-sdk",
      "template_variables": {
        "APP_ID_DBUS": "%s",
        "APP_PKGNAME_DBUS": "%s",
        "APP_PKGNAME": "%s",
        "APP_APPNAME": "%s",
        "APP_VERSION": "0.99.9~123",
        "CLICK_DIR": "%s"
      }
    }
  }
}''' % (pkgname, appname, dbus_id, dbus_pkgname, pkgname, appname,
            click_databases))
        self.assertEquals(expected, easyprof_manifest,
                          "Expected to get %s, got %s" % (expected,
                                                          easyprof_manifest))

    def test_parse_security_manifest_bad_symlink(self):
        '''Test being given a symlink and parsing the manifests'''
        c = self.clickstate
        c.add_package("com.ubuntu.developer.username.myapp", "0.1")
        security_json = '''{
  "policy_groups": [ "networking" ],
  "policy_version": 1.0
}'''
        c.add_app('sample-app', manifest=security_json)

        n = "com.ubuntu.developer.username.myapp_sample-app_0.1.json"
        fn = os.path.join(c.click_dir, n)
        shutil.move(os.path.dirname(c.click_pkgdir),
                    os.path.dirname(c.click_pkgdir) + '.new')
        try:
            click.ClickManifest(fn)
        except AppArmorException as e:
            self.assertTrue("from symlink" in str(e))
            return
        except Exception:
            raise
        raise Exception("Should have not found click manifest from symlink")

    def test_to_profiles(self):
        '''Test to_profiles()'''
        c = self.clickstate
        package = "com.ubuntu.developer.username.yourapp"
        appname = "sample-app"
        version = "0.3"
        c.add_package(package, version)
        security_json = '''{
  "policy_groups": [ "networking" ],
  "policy_version": 1.0
}'''
        c.add_app(appname, manifest=security_json)
        full_name = "%s_%s_%s" % (package, appname, version)

        cm = click.ClickManifest(os.path.join(c.click_dir,
                                 "%s.json" % full_name))
        easyprof_manifest = click.transform(cm)

        files = click.to_profiles(easyprof_manifest, self.tmpdir)
        self.assertTrue(len(files) == 1,
                        "to_profiles didn't return one profile:\n%s" % files)
        self.assertTrue(os.path.exists(files[0]), "'%s' does not exist" %
                                                  files[0])
        expected_fn = "click_%s" % (full_name)
        fn = os.path.basename(files[0])
        self.assertTrue(fn == expected_fn, "'%s' != '%s'" % (fn,
                                                             expected_fn))

    def test_to_profiles_existing_profile_same(self):
        '''Test to_profiles() with existing profile that is the same'''
        c = self.clickstate
        package = "com.ubuntu.developer.username.yourapp"
        appname = "sample-app"
        version = "0.3"
        c.add_package(package, version)
        security_json = '''{
  "policy_groups": [ "networking" ],
  "policy_version": 1.0
}'''
        c.add_app(appname, manifest=security_json)
        full_name = "%s_%s_%s" % (package, appname, version)

        cm = click.ClickManifest(os.path.join(c.click_dir,
                                 "%s.json" % full_name))
        easyprof_manifest = click.transform(cm)

        files = click.to_profiles(easyprof_manifest, self.tmpdir)
        self.assertTrue(len(files) == 1,
                        "to_profiles didn't return one profile:\n%s" % files)
        self.assertTrue(os.path.exists(files[0]), "'%s' does not exist" %
                                                  files[0])

        # Test that we don't change the time stamp of the original file if
        # there are no changes
        mtime = os.stat(files[0]).st_mtime
        time.sleep(1)

        files = click.to_profiles(easyprof_manifest, self.tmpdir)
        self.assertTrue(len(files) == 1,
                        "to_profiles didn't return one profile:\n%s" % files)
        self.assertTrue(os.path.exists(files[0]), "'%s' does not exist" %
                                                  files[0])

        cur_mtime = os.stat(files[0]).st_mtime
        self.assertTrue(mtime == cur_mtime, 'mtime is different')

    def test_to_profiles_existing_profile_different(self):
        '''Test to_profiles() with existing profile that is different'''
        c = self.clickstate
        package = "com.ubuntu.developer.username.yourapp"
        appname = "sample-app"
        version = "0.3"
        c.add_package(package, version)
        security_json = '''{
  "policy_groups": [ "networking" ],
  "policy_version": 1.0
}'''
        c.add_app(appname, manifest=security_json)
        full_name = "%s_%s_%s" % (package, appname, version)

        cm = click.ClickManifest(os.path.join(c.click_dir,
                                 "%s.json" % full_name))
        easyprof_manifest = click.transform(cm)

        files = click.to_profiles(easyprof_manifest, self.tmpdir)
        self.assertTrue(len(files) == 1,
                        "to_profiles didn't return one profile:\n%s" % files)
        self.assertTrue(os.path.exists(files[0]), "'%s' does not exist" %
                                                  files[0])

        # Test that we do change the time stamp of the original file if
        # there are changes
        mtime = os.stat(files[0]).st_mtime
        time.sleep(1)

        c2 = self.clickstate
        shutil.rmtree(c2.click_pkgdir)
        os.unlink(os.path.join(c2.click_dir, "%s.json" % full_name))

        c2.add_package(package, version)
        security_json = '''{
  "policy_groups": [ ],
  "policy_version": 1.0
}'''
        c2.add_app(appname, manifest=security_json)
        cm = click.ClickManifest(os.path.join(c2.click_dir,
                                 "%s.json" % full_name))
        easyprof_manifest = click.transform(cm)

        files = click.to_profiles(easyprof_manifest, self.tmpdir)
        self.assertTrue(len(files) == 1,
                        "to_profiles didn't return one profile:\n%s" % files)
        expected_fn = "click_%s" % (full_name)
        fn = os.path.basename(files[0])
        self.assertTrue(fn == expected_fn, "'%s' != '%s'" % (fn,
                                                             expected_fn))

        cur_mtime = os.stat(files[0]).st_mtime
        self.assertTrue(mtime != cur_mtime, 'mtime are the same')

    def test_to_profiles_nonexistent_dir(self):
        '''Test to_profiles() with non-existent directory'''
        c = self.clickstate
        package = "com.ubuntu.developer.username.yourapp"
        appname = "sample-app"
        version = "0.3"
        c.add_package(package, version)
        security_json = '''{
  "policy_groups": [ "networking" ],
  "policy_version": 1.0
}'''
        c.add_app(appname, manifest=security_json)
        full_name = "%s_%s_%s" % (package, appname, version)

        cm = click.ClickManifest(os.path.join(c.click_dir,
                                 "%s.json" % full_name))
        easyprof_manifest = click.transform(cm)

        didnt_exist_dir = os.path.join(self.tmpdir, "didnt_exist")
        files = []
        files = click.to_profiles(easyprof_manifest, didnt_exist_dir)
        self.assertTrue(len(files) == 1,
                        "to_profiles didn't return one profile:\n%s" % files)
        self.assertTrue(os.path.isdir(didnt_exist_dir), "Could not find " +
                        "%s" % didnt_exist_dir)

    def test_to_profiles_with_include(self):
        '''Test to_profiles() with include file'''
        c = self.clickstate
        package = "com.ubuntu.developer.username.yourapp"
        appname = "sample-app"
        version = "0.3"
        c.add_package(package, version)
        security_json = '''{
  "policy_groups": [ "networking" ],
  "policy_version": 1.0
}'''
        c.add_app(appname, manifest=security_json)
        full_name = "%s_%s_%s" % (package, appname, version)

        include = os.path.join(self.tmpdir, "test-inject.include")
        with open(include, "w+") as f:
            f.write('''  /foo r,\n''')
            f.close()

        include2 = os.path.join(self.tmpdir, "test-inject.include2")
        with open(include2, "w+") as f:
            f.write('''  /bar r,\n''')
            f.close()

        cm = click.ClickManifest(os.path.join(c.click_dir,
                                 "%s.json" % full_name))
        easyprof_manifest = click.transform(cm)

        files = click.to_profiles(easyprof_manifest, self.tmpdir,
                                  include=[include, include2])
        self.assertTrue(len(files) == 1,
                        "to_profiles didn't return one profile:\n%s" % files)
        self.assertTrue(os.path.exists(files[0]), "'%s' does not exist" %
                                                  files[0])
        expected_fn = "click_%s" % (full_name)
        fn = os.path.basename(files[0])
        self.assertTrue(fn == expected_fn, "'%s' != '%s'" % (fn,
                                                             expected_fn))

        with open(files[0], 'r') as f:
            contents = f.read()
            f.close()
        for s in ['# injected via click hook', 'test-inject.include',
                  'test-inject.include2']:
            self.assertTrue(s in contents, "Could not find '%s'" % s +
                            "in:\n%s" % contents)

    def test_to_profiles_without_include(self):
        '''Test to_profiles() without include file'''
        c = self.clickstate
        package = "com.ubuntu.developer.username.yourapp"
        appname = "sample-app"
        version = "0.3"
        c.add_package(package, version)
        security_json = '''{
  "policy_groups": [ "networking" ],
  "policy_version": 1.0
}'''
        c.add_app(appname, manifest=security_json)
        full_name = "%s_%s_%s" % (package, appname, version)

        cm = click.ClickManifest(os.path.join(c.click_dir,
                                 "%s.json" % full_name))
        easyprof_manifest = click.transform(cm)

        files = click.to_profiles(easyprof_manifest, self.tmpdir, include=[])
        self.assertTrue(len(files) == 1,
                        "to_profiles didn't return one profile:\n%s" % files)
        self.assertTrue(os.path.exists(files[0]), "'%s' does not exist" %
                                                  files[0])
        expected_fn = "click_%s" % (full_name)
        fn = os.path.basename(files[0])
        self.assertTrue(fn == expected_fn, "'%s' != '%s'" % (fn,
                                                             expected_fn))

        with open(files[0], 'r') as f:
            contents = f.read()
            f.close()
        for s in ['# injected via click hook', 'test-inject.include']:
            self.assertFalse(s in contents, "Found '%s' in:\n%s" % (
                             s, contents))

    def test_easyprof_profile_methods(self):
        '''Test EasyprofProfile methods'''
        newp = click.EasyprofProfile("foo")

        s = "test-string"
        self.assertTrue(newp.template is None)
        newp.template = s
        self.assertTrue(newp.template == s)

        self.assertTrue(newp.policyvendor is None)
        newp.policyvendor = s
        self.assertTrue(newp.policyvendor == s)

        self.assertTrue(newp.policyversion is None)
        newp.policyversion = 1.0
        self.assertTrue(newp.policyversion == 1.0)

        k = "test-key"
        self.assertTrue(k not in newp.profile['template_variables'])
        newp.add_variable(k, s)
        self.assertTrue(k in newp.profile['template_variables'])
        self.assertTrue(newp.profile['template_variables'][k] == s)

        e = "test-entry"
        self.assertTrue(e not in newp.profile['policy_groups'])
        newp.add_policygroup(e)
        self.assertTrue(e in newp.profile['policy_groups'])

        self.assertTrue('abstractions' not in newp.profile)
        newp.add_abstraction(e)
        self.assertTrue(e in newp.profile['abstractions'])

        self.assertTrue('read_path' not in newp.profile)
        newp.add_read_path(e)
        self.assertTrue(e in newp.profile['read_path'])

        self.assertTrue('write_path' not in newp.profile)
        newp.add_write_path(e)
        self.assertTrue(e in newp.profile['write_path'])

    def test_easyprof_profile_methods_for_duplicates(self):
        '''Test EasyprofProfile methods for duplicates'''
        newp = click.EasyprofProfile("foo")

        e = "test-entry"
        self.assertTrue(e not in newp.profile['policy_groups'])
        newp.add_policygroup(e)
        newp.add_policygroup(e)
        self.assertTrue(e in newp.profile['policy_groups'])
        self.assertEquals(1, newp.profile['policy_groups'].count(e))

        self.assertTrue('abstractions' not in newp.profile)
        newp.add_abstraction(e)
        newp.add_abstraction(e)
        self.assertTrue(e in newp.profile['abstractions'])
        self.assertEquals(1, newp.profile['abstractions'].count(e))

        self.assertTrue('read_path' not in newp.profile)
        newp.add_read_path(e)
        newp.add_read_path(e)
        self.assertTrue(e in newp.profile['read_path'])
        self.assertEquals(1, newp.profile['read_path'].count(e))

        self.assertTrue('write_path' not in newp.profile)
        newp.add_write_path(e)
        newp.add_write_path(e)
        self.assertTrue(e in newp.profile['write_path'])
        self.assertEquals(1, newp.profile['write_path'].count(e))

    def test_parse_manifest_name(self):
        '''Test parse_manifest_name()'''
        package = "com.ubuntu.developer.username.yourapp"
        appname = "sample-app"
        version = "0.3"
        manifest_name = "%s_%s_%s.json" % (package, appname, version)

        (p, a, v) = click.parse_manifest_name(manifest_name)
        self.assertTrue(p == package, "'%s' != '%s'" % (p, package))
        self.assertTrue(a == appname, "'%s' != '%s'" % (a, appname))
        self.assertTrue(v == version, "'%s' != '%s'" % (v, version))

    def test_parse_manifest_name_bad_no_json(self):
        '''Test parse_manifest_name() without .json'''
        package = "com.ubuntu.developer.username.yourapp"
        appname = "sample-app"
        version = "0.3"
        manifest_name = "%s_%s_%s" % (package, appname, version)

        try:
            click.parse_manifest_name(manifest_name)
        except AppArmorException:
            return
        except Exception:
            raise
        raise Exception("'%s' should be invalid" % (manifest_name))

    def test_parse_manifest_name_bad_name(self):
        '''Test parse_manifest_name() bad name'''
        package = "com.ubuntu.developer.username.yourapp"
        manifest_name = "%s.json" % package

        try:
            click.parse_manifest_name(manifest_name)
        except AppArmorException:
            return
        except Exception:
            raise
        raise Exception("'%s' should be invalid" % (manifest_name))

    def test_get_framework_base_version_subframework(self):
        '''Test get_framework_base_version() (subframework)'''
        for k in click.framework_transforms.keys():
            if k == 'ubuntu-sdk-13.10':  # 13.10 doesn't have subframeworks
                continue
            for sub in ['-dev', '-dev1',
                        '-html-dev1', '-html',
                        '-papi-dev2', '-papi',
                        '-qml-dev3', 'qml']:
                framework = "%s%s" % (k, sub)
                framework_base = click.get_framework_base_version(framework)
                self.assertTrue(framework_base == k,
                                "%s != %s" % (framework_base, k))

    def test_get_framework_base_version_1310(self):
        '''Test get_framework_base_version() (13.10)'''
        framework = 'ubuntu-sdk-13.10'
        framework_base = click.get_framework_base_version(framework)
        self.assertTrue(framework_base == framework,
                        "%s != %s" % (framework_base, framework))

    def test_get_framework_base_version_nonexistent(self):
        '''Test get_framework_base_version() (nonexistent)'''
        framework = 'nonexistsent'
        try:
            click.get_framework_base_version(framework)
        except click.AppArmorExceptionClickFrameworkNotFound as e:
            self.assertTrue("Unknown framework" in str(e))
            return
        except Exception:
            raise
        raise Exception("Should have failed on nonexistent framework")

    def test_get_policy_version_for_framework(self):
        '''Test get_policy_version_for_framework() (subframework)'''
        for k in click.framework_transforms.keys():
            if k == 'ubuntu-sdk-13.10':  # 13.10 doesn't have subframeworks
                continue
            for sub in ['-dev', '-dev1',
                        '-html-dev1', '-html',
                        '-papi-dev2', '-papi',
                        '-qml-dev3', 'qml']:
                framework = "%s%s" % (k, sub)
                policy_version = click.get_policy_version_for_framework(
                    framework)
                recommended = click.framework_transforms[k][1]
                self.assertTrue(policy_version == recommended,
                                "%s != %s" % (policy_version, recommended))

    def test_get_policy_version_for_framework_1310(self):
        '''Test get_policy_version_for_framework() (13.10)'''
        framework = 'ubuntu-sdk-13.10'
        policy_version = click.get_policy_version_for_framework(framework)
        recommended = click.framework_transforms[framework][1]
        self.assertTrue(policy_version == recommended,
                        "%s != %s" % (policy_version, recommended))

    def test_get_policy_version_for_framework_nonexistent(self):
        '''Test get_policy_version_for_framework() (nonexistent)'''
        framework = 'nonexistsent'
        try:
            click.get_policy_version_for_framework(framework)
        except click.AppArmorExceptionClickFrameworkNotFound as e:
            self.assertTrue("Unknown framework" in str(e))
            return
        except Exception:
            raise
        raise Exception("Should have failed on nonexistent framework")


class AppArmorManifestSynchronization(unittest.TestCase):
    def setUp(self):
        self.tmpdir = tempfile.mkdtemp(prefix="aa-manifest-consistency-")
        self.clickstate = ClickState(self.tmpdir)
        self.maxDiff = None

    def tearDown(self):
        if os.path.exists(self.tmpdir):
            shutil.rmtree(self.tmpdir)

    def test_two_equal_directories(self):
        '''Test two equal directories'''
        c = self.clickstate
        clicks = ["alpha_beta_gamma", "click_click_version",
                  "wat_no-really_wat"]
        for cname in clicks:
            with open(os.path.join(c.click_dir, '%s.json' %
                      (cname)), 'w+') as f:
                f.write('invalid json here')
            with open(os.path.join(c.profiles_dir, 'click_%s' %
                                   (cname)), 'w+') as f:
                f.write('profile %s { }' % (cname))

        expected = []
        result = click.get_missing_profiles(c.click_dir, c.profiles_dir)
        self.assertEquals(expected, result,
                          "Expected to get no profiles, got %s" % (result))
        result = click.get_missing_clickhooks(c.click_dir, c.profiles_dir)
        self.assertEquals(expected, result,
                          "Expected to get no click hooks, got %s" % (result))

    def test_two_empty_directories_for_profiles(self):
        '''Test two empty directories returns no new needed profiles'''
        c = self.clickstate

        expected = []
        result = click.get_missing_profiles(c.click_dir, c.profiles_dir)
        self.assertEquals(expected, result,
                          "Expected to get no profiles, got %s" % (result))

    def test_two_empty_directories_for_clicks(self):
        '''Test two empty directories returns no removed click hooks'''
        c = self.clickstate

        expected = []
        result = click.get_missing_clickhooks(c.click_dir, c.profiles_dir)
        self.assertEquals(expected, result,
                          "Expected to get no clickhooks, got %s" % (result))

    def test_versus_empty_profiles_directory(self):
        '''Test against empty profiles directory'''
        c = self.clickstate
        clicks = ["alpha_beta_gamma.json", "click_click_version.json",
                  "wat_no-really_wat.json"]
        for cname in clicks:
            with open(os.path.join(c.click_dir, cname), 'w+') as f:
                f.write('invalid json here')

        expected = set(clicks)
        result = set(click.get_missing_profiles(c.click_dir, c.profiles_dir))
        self.assertEquals(expected, result,
                          "Expected to get %s profiles, got %s" % (expected,
                                                                   result))

    def test_versus_empty_clicks_directory(self):
        '''Test against empty clicks directory'''
        c = self.clickstate
        clicks = ["alpha_beta_gamma", "click_click_version",
                  "wat_no-really_wat"]
        for cname in clicks:
            with open(os.path.join(c.profiles_dir, 'click_%s' %
                                   (cname)), 'w+') as f:
                f.write('profile %s { }' % (cname))

        expected = set(["%s%s" % (click.AppName._CLICK_PREFIX, x)
                       for x in clicks])
        result = set(click.get_missing_clickhooks(c.click_dir, c.profiles_dir))
        self.assertEquals(expected, result,
                          "Expected to get %s hooks, got %s" % (expected,
                                                                result))

    def test_two_unequal_directories(self):
        '''Test two unequal directories'''
        c = self.clickstate
        expected_clicks = ['missing_click_profile.json',
                           'another-missing_click_profile.json']
        expected_profiles = ['%sremoved_click_package' %
                             (click.AppName._CLICK_PREFIX)]
        clicks = ["alpha_beta_gamma.json", "click_click_version.json",
                  "wat_no-really_wat.json"]
        profiles = ["%s%s" % (click.AppName._CLICK_PREFIX,
                              x[:-len('.json')]) for x in clicks]
        clicks.extend(expected_clicks)
        profiles.extend(expected_profiles)
        for cname in clicks:
            with open(os.path.join(c.click_dir, cname), 'w+') as f:
                f.write('invalid json here')
        for pname in profiles:
            with open(os.path.join(c.profiles_dir, pname), 'w+') as f:
                f.write('profile %s { }' % (pname))

        result = set(click.get_missing_profiles(c.click_dir, c.profiles_dir))
        self.assertEquals(set(expected_clicks), result,
                          "Expected to get '%s' missing profiles, got %s" %
                          (set(expected_clicks), result))
        result = set(click.get_missing_clickhooks(c.click_dir, c.profiles_dir))
        self.assertEquals(set(expected_profiles), result,
                          "Expected to get '%s' missing click hooks, got %s" %
                          (set(expected_profiles), result))

    def test_two_unequal_directories_bad_profile_filename(self):
        '''Test two unequal directories (bad profile_filename)'''
        c = self.clickstate
        clicks = ["alpha_beta_gamma", "click_click_version",
                  "wat_no-really_wat"]
        for cname in clicks:
            with open(os.path.join(c.click_dir, '%s.json' %
                      (cname)), 'w+') as f:
                f.write('invalid json here')
            with open(os.path.join(c.profiles_dir, 'badformat_%s' %
                                   (cname)), 'w+') as f:
                f.write('profile %s { }' % (cname))

        expected = []
        result = click.get_missing_clickhooks(c.click_dir, c.profiles_dir)
        self.assertEquals(expected, result,
                          "Expected to get no click hooks, got %s" % (result))

    def test_two_equal_directories_new_symlink(self):
        '''Test two equal directories with new symlink (LP: #1291549)'''
        c = self.clickstate
        clicks = ["alpha_beta_gamma", "click_click_version",
                  "wat_no-really_wat"]
        for cname in clicks:
            with open(os.path.join(c.click_dir, '%s.json' %
                      (cname)), 'w+') as f:
                f.write('invalid json here')
            with open(os.path.join(c.profiles_dir, 'click_%s' %
                                   (cname)), 'w+') as f:
                f.write('profile %s { }' % (cname))

        # Click hooks not updated yet, so everything should be the same
        expected = []
        result = click.get_missing_profiles(c.click_dir, c.profiles_dir)
        self.assertEquals(expected, result,
                          "Expected to get no profiles, got %s" % (result))
        result = click.get_missing_clickhooks(c.click_dir, c.profiles_dir)
        self.assertEquals(expected, result,
                          "Expected to get no click hooks, got %s" % (result))

        time.sleep(1)
        clicks = ["alpha_beta_gamma", "click_click_version"]
        for cname in clicks:
            with open(os.path.join(c.click_dir, '%s.json' %
                      (cname)), 'w+') as f:
                f.write('invalid json here')

        expected = []
        result = click.get_missing_clickhooks(c.click_dir, c.profiles_dir)
        self.assertEquals(expected, result,
                          "Expected to get no click hooks, got %s" % (result))
        expected = len(clicks)
        result = click.get_missing_profiles(c.click_dir, c.profiles_dir)
        self.assertEquals(expected, len(result),
                          "Expected to get %d profiles, got %s:\n" %
                          (expected, len(result)))

    def test_two_equal_directories_new_override(self):
        '''Test two equal directories with new overrides'''
        c = self.clickstate
        clicks = ["alpha_beta_gamma", "click_click_version",
                  "wat_no-really_wat"]
        for cname in clicks:
            with open(os.path.join(c.click_dir, '%s.json' %
                      (cname)), 'w+') as f:
                f.write('invalid json here')
                f.close()
            with open(os.path.join(c.click_dir, '%s.json.override' %
                      (cname)), 'w+') as f:
                f.write('invalid json here')
                f.close()
            with open(os.path.join(c.profiles_dir, 'click_%s' %
                                   (cname)), 'w+') as f:
                f.write('profile %s { }' % (cname))
                f.close()

        # Click hooks not updated yet, so everything should be the same
        expected = []
        result = click.get_missing_profiles(c.click_dir, c.profiles_dir)
        self.assertEquals(expected, result,
                          "Expected to get no profiles, got %s" % (result))
        result = click.get_missing_clickhooks(c.click_dir, c.profiles_dir)
        self.assertEquals(expected, result,
                          "Expected to get no click hooks, got %s" % (result))

        time.sleep(1)
        clicks = ["alpha_beta_gamma", "click_click_version"]
        for cname in clicks:
            with open(os.path.join(c.click_dir, '%s.json.override' %
                      (cname)), 'w+') as f:
                f.write('invalid json here')
                f.close()

        expected = []
        result = click.get_missing_clickhooks(c.click_dir, c.profiles_dir)
        self.assertEquals(expected, result,
                          "Expected to get no click hooks, got %s" % (result))
        expected = len(clicks)
        result = click.get_missing_profiles(c.click_dir, c.profiles_dir)
        self.assertEquals(expected, len(result),
                          "Expected to get %d profiles, got %s:\n" %
                          (expected, len(result)))

    def test_two_equal_directories_new_additional(self):
        '''Test two equal directories with new additional accesses'''
        c = self.clickstate
        clicks = ["alpha_beta_gamma", "click_click_version",
                  "wat_no-really_wat"]
        for cname in clicks:
            with open(os.path.join(c.click_dir, '%s.json' %
                      (cname)), 'w+') as f:
                f.write('invalid json here')
                f.close()
            with open(os.path.join(c.click_dir, '%s.json.additional' %
                      (cname)), 'w+') as f:
                f.write('invalid json here')
                f.close()
            with open(os.path.join(c.profiles_dir, 'click_%s' %
                                   (cname)), 'w+') as f:
                f.write('profile %s { }' % (cname))
                f.close()

        # Click hooks not updated yet, so everything should be the same
        expected = []
        result = click.get_missing_profiles(c.click_dir, c.profiles_dir)
        self.assertEquals(expected, result,
                          "Expected to get no profiles, got %s" % (result))
        result = click.get_missing_clickhooks(c.click_dir, c.profiles_dir)
        self.assertEquals(expected, result,
                          "Expected to get no click hooks, got %s" % (result))

        time.sleep(1)
        clicks = ["alpha_beta_gamma", "click_click_version"]
        for cname in clicks:
            with open(os.path.join(c.click_dir, '%s.json.additional' %
                      (cname)), 'w+') as f:
                f.write('invalid json here')
                f.close()

        expected = []
        result = click.get_missing_clickhooks(c.click_dir, c.profiles_dir)
        self.assertEquals(expected, result,
                          "Expected to get no click hooks, got %s" % (result))
        expected = len(clicks)
        result = click.get_missing_profiles(c.click_dir, c.profiles_dir)
        self.assertEquals(expected, len(result),
                          "Expected to get %d profiles, got %s:\n" %
                          (expected, len(result)))


class AppArmorManifestOverride(unittest.TestCase):
    def setUp(self):
        self.tmpdir = tempfile.mkdtemp(prefix="aa-manifest-override-")
        self.clickstate = ClickState(self.tmpdir)
        self.maxDiff = None

    def tearDown(self):
        if os.path.exists(self.tmpdir):
            shutil.rmtree(self.tmpdir)

    def _stub_override(self, sec_snip, override_snip, fn_type=None):
        c = self.clickstate
        c.add_package("com.ubuntu.developer.username.myapp", "0.1")
        security_json = '''{
  %s,
  "policy_version": 1.0
}''' % sec_snip

        if override_snip is None:
            override_json = ''
        else:
            override_json = '''{
  %s
}''' % override_snip

        appname = 'sample-app'
        c.add_app(appname, manifest=security_json, override=override_json,
                  fn_type=fn_type)
        n = "com.ubuntu.developer.username.myapp_%s_0.1.json" % appname
        nbase = n.strip(".json")

        return (c, n, nbase)

    def test_valid_override(self):
        '''Test valid override'''
        sec = '"policy_groups": [ "networking" ]'
        over = '"policy_groups": [ "networking" ]'
        (c, n, nbase) = self._stub_override(sec, over)

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 0
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "networking")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\noverride:\n%s" % (expected, count, sec, over))

    def test_valid_override_nonpresent(self):
        '''Test valid override - remove nonpresent group'''
        sec = '"policy_groups": [ "networking" ]'
        over = '"policy_groups": [ "contacts" ]'
        (c, n, nbase) = self._stub_override(sec, over)

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 1
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "networking")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\noverride:\n%s" % (expected, count, sec, over))

        expected = 0
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "contacts")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\noverride:\n%s" % (expected, count, sec, over))

    def test_valid_override_multiple_same(self):
        '''Test valid override - multiple networking'''
        sec = '"policy_groups": [ "networking", "networking" ]'
        over = '"policy_groups": [ "networking" ]'
        (c, n, nbase) = self._stub_override(sec, over)

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 0
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "networking")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\noverride:\n%s" % (expected, count, sec, over))

    def test_valid_override_multiple_different(self):
        '''Test valid override - multiple (policy_groups, abstractions)'''
        sec = '''
  "policy_groups": [ "networking", "networking" ],
  "abstractions": [ "audio", "bash" ]
'''
        over = '"policy_groups": [ "networking" ]'
        (c, n, nbase) = self._stub_override(sec, over)

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 0
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "networking")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\noverride:\n%s" % (expected, count, sec, over))

    def test_valid_override_nothing(self):
        '''Test valid override - nothing'''
        sec = '''
  "policy_groups": [ "audio", "video" ],
  "abstractions": [ "audio", "video" ],
  "read_path": [ "audio", "video" ],
  "write_path": [ "audio", "video" ]
'''
        over = '''
  "policy_groups": [ ],
  "abstractions": [ ],
  "read_path": [ ],
  "write_path": [ ]
'''
        (c, n, nbase) = self._stub_override(sec, over)

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        for i in ["abstractions", "policy_groups", "read_path",
                  "write_path"]:
            expected = 1
            count = easyprof_manifest["profiles"][nbase][i].count(
                "audio")
            self.assertEquals(expected, count,
                              "Expected to get %d, got %d:\noriginal:\n%s"
                              "\noverride:\n%s" % (expected, count, sec, over))
            count = easyprof_manifest["profiles"][nbase][i].count(
                "video")
            self.assertEquals(expected, count,
                              "Expected to get %d, got %d:\noriginal:\n%s"
                              "\noverride:\n%s" % (expected, count, sec, over))

    def test_valid_override_one(self):
        '''Test valid override - one from all'''
        sec = '''
  "policy_groups": [ "foo", "bar" ],
  "abstractions": [ "foo", "bar" ],
  "read_path": [ "foo", "bar" ],
  "write_path": [ "foo", "bar" ]
'''
        over = '''
  "policy_groups": [ "foo" ],
  "abstractions": [ "foo" ],
  "read_path": [ "foo" ],
  "write_path": [ "foo" ]
'''
        (c, n, nbase) = self._stub_override(sec, over)

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        for i in ["abstractions", "policy_groups", "read_path",
                  "write_path"]:
            expected = 0
            count = easyprof_manifest["profiles"][nbase][i].count(
                "foo")
            self.assertEquals(expected, count,
                              "Expected to get %d, got %d:\noriginal:\n%s"
                              "\noverride:\n%s" % (expected, count, sec, over))

        for i in ["abstractions", "policy_groups", "read_path",
                  "write_path"]:
            expected = 1
            count = easyprof_manifest["profiles"][nbase][i].count(
                "bar")
            self.assertEquals(expected, count,
                              "Expected to get %d, got %d:\noriginal:\n%s"
                              "\noverride:\n%s" % (expected, count, sec, over))

    def test_override_invalid_match1(self):
        '''Test override invalid match -- short'''
        sec = '"policy_groups": [ "networking" ]'
        over = '"policy_groups": [ "networkin" ]'
        (c, n, nbase) = self._stub_override(sec, over)

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 1
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "networking")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\noverride:\n%s" % (expected, count, sec, over))

    def test_override_invalid_match2(self):
        '''Test override invalid match -- long'''
        sec = '"policy_groups": [ "networking" ]'
        over = '"policy_groups": [ "networkingg" ]'
        (c, n, nbase) = self._stub_override(sec, over)

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 1
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "networking")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\noverride:\n%s" % (expected, count, sec, over))

    def test_override_invalid_match3(self):
        '''Test override invalid match -- case'''
        sec = '"policy_groups": [ "networking" ]'
        over = '"policy_groups": [ "NeTwOrKiNg" ]'
        (c, n, nbase) = self._stub_override(sec, over)

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 1
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "networking")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\noverride:\n%s" % (expected, count, sec, over))

    def test_override_invalid_match_empty(self):
        '''Test override invalid match -- empty'''
        sec = '"policy_groups": [ "networking" ]'
        over = '"policy_groups": [ ]'
        (c, n, nbase) = self._stub_override(sec, over)

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 1
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "networking")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\noverride:\n%s" % (expected, count, sec, over))

    def test_override_invalid_match_nonexistent1(self):
        '''Test override invalid match -- nonexistent'''
        sec = '"policy_groups": [ "networking" ]'
        over = '"nonexistent": [ "networking" ]'
        (c, n, nbase) = self._stub_override(sec, over)

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 1
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "networking")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\noverride:\n%s" % (expected, count, sec, over))

    def test_override_invalid_match_nonexistent2(self):
        '''Test override invalid match -- nonexistent read_path'''
        sec = '"policy_groups": [ "networking" ]'
        over = '"read_path": [ "/etc/fstab" ]'
        (c, n, nbase) = self._stub_override(sec, over)

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 0
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "read_path")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\noverride:\n%s" % (expected, count, sec, over))

    def test_override_malformed1(self):
        '''Test override malformed - not a list'''
        sec = '"policy_groups": [ "networking" ]'
        over = '"policy_groups": "networking"'
        (c, n, nbase) = self._stub_override(sec, over)

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 1
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "networking")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\noverride:\n%s" % (expected, count, sec, over))

    def test_override_malformed2(self):
        '''Test override malformed - extra comma'''
        sec = '"policy_groups": [ "networking" ]'
        over = '"policy_groups": [ "networking" ],'
        (c, n, nbase) = self._stub_override(sec, over)

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 1
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "networking")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\noverride:\n%s" % (expected, count, sec, over))

    def test_override_malformed3(self):
        '''Test override malformed - missing quote'''
        sec = '"policy_groups": [ "networking" ]'
        over = '"policy_groups: [ "networking" ]'
        (c, n, nbase) = self._stub_override(sec, over)

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 1
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "networking")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\noverride:\n%s" % (expected, count, sec, over))

    def test_override_malformed4(self):
        '''Test override malformed - empty file'''
        sec = '"policy_groups": [ "networking" ]'
        over = None
        (c, n, nbase) = self._stub_override(sec, over)

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 1
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "networking")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\noverride:\n%s" % (expected, count, sec, over))

    def test_override_malformed5(self):
        '''Test override malformed - empty dict()'''
        sec = '"policy_groups": [ "networking" ]'
        over = ''
        (c, n, nbase) = self._stub_override(sec, over)

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 1
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "networking")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\noverride:\n%s" % (expected, count, sec, over))

    def test_valid_override_pkgname(self):
        '''Test valid override - pkgname'''
        sec = '"policy_groups": [ "networking" ]'
        over = '"policy_groups": [ "networking" ]'
        (c, n, nbase) = self._stub_override(sec, over, fn_type="package")

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 0
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "networking")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\noverride:\n%s" % (expected, count, sec, over))

    def test_valid_override_appname(self):
        '''Test valid override - appname'''
        sec = '"policy_groups": [ "networking" ]'
        over = '"policy_groups": [ "networking" ]'
        (c, n, nbase) = self._stub_override(sec, over, fn_type="appname")

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 0
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "networking")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\noverride:\n%s" % (expected, count, sec, over))

    def test_valid_override_appid_first(self):
        '''Test valid override - skip pkgname.json.override (keep group)'''
        sec = '"policy_groups": [ "networking" ]'
        over = '"policy_groups": [ ]'
        (c, n, nbase) = self._stub_override(sec, over)

        # This is less-specific, so it should be ignored
        (pkgname, appname, version) = nbase.split("_")
        fn = os.path.join(c.click_dir, "%s.json.override" % (pkgname))
        json2 = json.dumps({"policy_groups": ["networking"]})
        with open(fn, "w+", encoding="UTF-8") as f:
            f.write("%s\n" % json2)
            f.close()

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 1
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "networking")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\noverride:\n%s\njson2:\n%s" % (expected, count,
                                                           sec, over, json2))

    def test_valid_override_appid_first2(self):
        '''Test valid override - skip pkgname_appname.json.override'''
        sec = '"policy_groups": [ "networking" ]'
        over = '"policy_groups": [ ]'
        (c, n, nbase) = self._stub_override(sec, over)

        # This is less-specific, so it should be ignored
        (pkgname, appname, version) = nbase.split("_")
        fn = os.path.join(c.click_dir, "%s_%s.json.override" % (pkgname,
                                                                appname))
        json2 = json.dumps({"policy_groups": ["networking"]})
        with open(fn, "w+", encoding="UTF-8") as f:
            f.write("%s\n" % json2)
            f.close()

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 1
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "networking")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\noverride:\n%s\njson2:\n%s" % (expected, count,
                                                           sec, over, json2))

    def test_valid_override_appid_first3(self):
        '''Test valid override - skip pkgname.json.override (remove group)'''
        sec = '"policy_groups": [ "networking" ]'
        over = '"policy_groups": [ "networking" ]'
        (c, n, nbase) = self._stub_override(sec, over)

        # This is less-specific, so it should be ignored
        (pkgname, appname, version) = nbase.split("_")
        fn = os.path.join(c.click_dir, "%s.json.override" % (pkgname))
        json2 = json.dumps({"policy_groups": []})
        with open(fn, "w+", encoding="UTF-8") as f:
            f.write("%s\n" % json2)
            f.close()

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 0
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "networking")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\noverride:\n%s\njson2:\n%s" % (expected, count,
                                                           sec, over, json2))


class AppArmorManifestAdditional(unittest.TestCase):
    def setUp(self):
        self.tmpdir = tempfile.mkdtemp(prefix="aa-manifest-additional-")
        self.clickstate = ClickState(self.tmpdir)
        self.maxDiff = None

    def tearDown(self):
        if os.path.exists(self.tmpdir):
            shutil.rmtree(self.tmpdir)

    def _stub_additional(self, sec_snip, additional_snip, fn_type=None):
        c = self.clickstate
        c.add_package("com.ubuntu.developer.username.myapp", "0.1")
        security_json = '''{
  %s,
  "policy_version": 1.0
}''' % sec_snip

        if additional_snip is None:
            additional_json = ''
        else:
            additional_json = '''{
  %s
}''' % additional_snip

        appname = 'sample-app'
        c.add_app(appname, manifest=security_json, additional=additional_json,
                  fn_type=fn_type)
        n = "com.ubuntu.developer.username.myapp_%s_0.1.json" % appname
        nbase = n.strip(".json")

        return (c, n, nbase)

    def test_valid_additional(self):
        '''Test valid additional'''
        sec = '"policy_groups": [ ]'
        add = '"policy_groups": [ "location" ]'
        (c, n, nbase) = self._stub_additional(sec, add)

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 1
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "location")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\nadditional:\n%s" % (expected, count, sec, add))

    def test_valid_additional_nonpresent(self):
        '''Test valid additional - add nonpresent group'''
        sec = '"policy_groups": [ "location" ]'
        add = '"policy_groups": [ "contacts" ]'
        (c, n, nbase) = self._stub_additional(sec, add)

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 1
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "location")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\nadditional:\n%s" % (expected, count, sec, add))

        expected = 1
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "contacts")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\nadditional:\n%s" % (expected, count, sec, add))

    def test_valid_additional_multiple_same(self):
        '''Test valid additional - multiple location'''
        sec = '"policy_groups": [ ]'
        add = '"policy_groups": [ "location", "location" ]'
        (c, n, nbase) = self._stub_additional(sec, add)

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 1
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "location")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\nadditional:\n%s" % (expected, count, sec, add))

    def test_valid_additional_multiple_different(self):
        '''Test valid additional - multiple (policy_groups, abstractions)'''
        sec = '''
  "policy_groups": [ "networking" ],
  "abstractions": [ "audio", "bash" ]
'''
        add = '"policy_groups": [ "location", "location" ]'
        (c, n, nbase) = self._stub_additional(sec, add)

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 1
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "location")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\nadditional:\n%s" % (expected, count, sec, add))

        expected = 1
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "networking")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\nadditional:\n%s" % (expected, count, sec, add))

    def test_valid_additional_nothing(self):
        '''Test valid additional - nothing'''
        sec = '''
  "policy_groups": [ "audio", "video" ],
  "abstractions": [ "audio", "video" ],
  "read_path": [ "audio", "video" ],
  "write_path": [ "audio", "video" ]
'''
        add = '''
  "policy_groups": [ ],
  "abstractions": [ ],
  "read_path": [ ],
  "write_path": [ ]
'''
        (c, n, nbase) = self._stub_additional(sec, add)

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        for i in ["abstractions", "policy_groups", "read_path",
                  "write_path"]:
            expected = 1
            count = easyprof_manifest["profiles"][nbase][i].count(
                "audio")
            self.assertEquals(expected, count,
                              "Expected to get %d, got %d:\noriginal:\n%s"
                              "\nadditional:\n%s" % (expected, count, sec,
                                                     add))
            count = easyprof_manifest["profiles"][nbase][i].count(
                "video")
            self.assertEquals(expected, count,
                              "Expected to get %d, got %d:\noriginal:\n%s"
                              "\nadditional:\n%s" % (expected, count, sec,
                                                     add))

    def test_valid_additional_one(self):
        '''Test valid additional - one from all'''
        sec = '''
  "policy_groups": [ "foo" ],
  "abstractions": [ "foo" ],
  "read_path": [ "foo" ],
  "write_path": [ "foo" ]
'''
        add = '''
  "policy_groups": [ "foo", "bar" ],
  "abstractions": [ "foo", "bar" ],
  "read_path": [ "foo", "bar" ],
  "write_path": [ "foo", "bar" ]
'''
        (c, n, nbase) = self._stub_additional(sec, add)

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        for i in ["abstractions", "policy_groups", "read_path",
                  "write_path"]:
            expected = 1
            count = easyprof_manifest["profiles"][nbase][i].count(
                "foo")
            self.assertEquals(expected, count,
                              "Expected to get %d, got %d:\noriginal:\n%s"
                              "\nadditional:\n%s" % (expected, count, sec,
                                                     add))

        for i in ["abstractions", "policy_groups", "read_path",
                  "write_path"]:
            expected = 1
            count = easyprof_manifest["profiles"][nbase][i].count(
                "bar")
            self.assertEquals(expected, count,
                              "Expected to get %d, got %d:\noriginal:\n%s"
                              "\nadditional:\n%s" % (expected, count, sec,
                                                     add))

    def test_additional_invalid_match_empty(self):
        '''Test additional invalid match -- empty'''
        sec = '"policy_groups": [ "location" ]'
        add = '"policy_groups": [ ]'
        (c, n, nbase) = self._stub_additional(sec, add)

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 1
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "location")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\nadditional:\n%s" % (expected, count, sec, add))

    def test_additional_invalid_match_nonexistent(self):
        '''Test additional invalid match -- nonexistent'''
        sec = '"policy_groups": [ "networking" ]'
        add = '"nonexistent": [ "location" ]'
        (c, n, nbase) = self._stub_additional(sec, add)

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 1
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "networking")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\nadditional:\n%s" % (expected, count, sec, add))

        expected = 0
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "location")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\nadditional:\n%s" % (expected, count, sec, add))

    def test_additional_valid_match_nonexistent(self):
        '''Test additional match -- nonexistent read_path'''
        sec = '"policy_groups": [ "location" ]'
        add = '"read_path": [ "/etc/fstab" ]'
        (c, n, nbase) = self._stub_additional(sec, add)

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 1
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "location")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\nadditional:\n%s" % (expected, count, sec, add))

        expected = 0
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "/etc/fstab")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\nadditional:\n%s" % (expected, count, sec, add))

        expected = 1
        count = easyprof_manifest["profiles"][nbase]["read_path"].count(
            "/etc/fstab")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\nadditional:\n%s" % (expected, count, sec, add))

        expected = 0
        count = easyprof_manifest["profiles"][nbase]["read_path"].count(
            "location")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\nadditional:\n%s" % (expected, count, sec, add))

    def test_additional_malformed1(self):
        '''Test additional malformed - not a list'''
        sec = '"policy_groups": [ "networking" ]'
        add = '"policy_groups": "location"'
        (c, n, nbase) = self._stub_additional(sec, add)

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 1
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "networking")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\nadditional:\n%s" % (expected, count, sec, add))

        expected = 0
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "location")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\nadditional:\n%s" % (expected, count, sec, add))

    def test_additional_malformed2(self):
        '''Test additional malformed - extra comma'''
        sec = '"policy_groups": [ ]'
        add = '"policy_groups": [ "location" ],'
        (c, n, nbase) = self._stub_additional(sec, add)

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 0
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "location")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\nadditional:\n%s" % (expected, count, sec, add))

    def test_additional_malformed3(self):
        '''Test additional malformed - missing quote'''
        sec = '"policy_groups": [ ]'
        add = '"policy_groups: [ "location" ]'
        (c, n, nbase) = self._stub_additional(sec, add)

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 0
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "location")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\nadditional:\n%s" % (expected, count, sec, add))

    def test_additional_malformed4(self):
        '''Test additional malformed - empty file'''
        sec = '"policy_groups": [ "location" ]'
        add = None
        (c, n, nbase) = self._stub_additional(sec, add)

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 1
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "location")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\nadditional:\n%s" % (expected, count, sec, add))

    def test_additional_malformed5(self):
        '''Test additional malformed - empty dict()'''
        sec = '"policy_groups": [ "location" ]'
        add = ''
        (c, n, nbase) = self._stub_additional(sec, add)

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 1
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "location")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\nadditional:\n%s" % (expected, count, sec, add))

    def test_valid_additional_pkgname(self):
        '''Test valid additional - pkgname (add group)'''
        sec = '"policy_groups": [ "networking" ]'
        add = '"policy_groups": [ "location" ]'
        (c, n, nbase) = self._stub_additional(sec, add, fn_type="appname")

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 1
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "location")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\nadditional:\n%s" % (expected, count, sec, add))

    def test_valid_additional_appname(self):
        '''Test valid additional - appname'''
        sec = '"policy_groups": [ "networking" ]'
        add = '"policy_groups": [ "location" ]'
        (c, n, nbase) = self._stub_additional(sec, add, fn_type="appname")

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 1
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "location")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\nadditional:\n%s" % (expected, count, sec, add))

    def test_valid_additional_appid_first(self):
        '''Test valid additional - skip pkgname.json.additional (no group)'''
        sec = '"policy_groups": [ "networking" ]'
        add = '"policy_groups": [ ]'
        (c, n, nbase) = self._stub_additional(sec, add)

        # This is less-specific, so it should be ignored
        (pkgname, appname, version) = nbase.split("_")
        fn = os.path.join(c.click_dir, "%s.json.additional" % (pkgname))
        json2 = json.dumps({"policy_groups": ["location"]})
        with open(fn, "w+", encoding="UTF-8") as f:
            f.write("%s\n" % json2)
            f.close()

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 0
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "location")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\nadditional:\n%s\njson2:\n%s" % (expected, count,
                                                             sec, add, json2))

    def test_valid_additional_appid_first2(self):
        '''Test valid additional - skip pkgname_appname.json.additional'''
        sec = '"policy_groups": [ "networking" ]'
        add = '"policy_groups": [ ]'
        (c, n, nbase) = self._stub_additional(sec, add)

        # This is less-specific, so it should be ignored
        (pkgname, appname, version) = nbase.split("_")
        fn = os.path.join(c.click_dir, "%s_%s.json.additional" % (pkgname,
                                                                  appname))
        json2 = json.dumps({"policy_groups": ["location"]})
        with open(fn, "w+", encoding="UTF-8") as f:
            f.write("%s\n" % json2)
            f.close()

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 0
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "location")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\nadditional:\n%s\njson2:\n%s" % (expected, count,
                                                             sec, add, json2))

    def test_valid_additional_appid_first3(self):
        '''Test valid additional - skip pkgname.json.additional (add group)
        '''
        sec = '"policy_groups": [ "networking" ]'
        add = '"policy_groups": [ "location" ]'
        (c, n, nbase) = self._stub_additional(sec, add)

        # This is less-specific, so it should be ignored
        (pkgname, appname, version) = nbase.split("_")
        fn = os.path.join(c.click_dir, "%s.json.additional" % (pkgname))
        json2 = json.dumps({"policy_groups": []})
        with open(fn, "w+", encoding="UTF-8") as f:
            f.write("%s\n" % json2)
            f.close()

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 1
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "location")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\nadditional:\n%s\njson2:\n%s" % (expected, count,
                                                             sec, add, json2))


class AppArmorManifestAdditionalWithOverride(unittest.TestCase):
    def setUp(self):
        self.tmpdir = tempfile.mkdtemp(prefix="aa-manifest-add+over-")
        self.clickstate = ClickState(self.tmpdir)
        self.maxDiff = None

    def tearDown(self):
        if os.path.exists(self.tmpdir):
            shutil.rmtree(self.tmpdir)

    def _stub_keys(self, sec_snip, override_snip, additional_snip):
        c = self.clickstate
        c.add_package("com.ubuntu.developer.username.myapp", "0.1")

        security_json = '''{
  %s,
  "policy_version": 1.0
}''' % sec_snip

        if additional_snip is None:
            additional_json = ''
        else:
            additional_json = '''{
  %s
}''' % additional_snip

        if override_snip is None:
            override_json = ''
        else:
            override_json = '''{
  %s
}''' % override_snip

        appname = 'sample-app'
        c.add_app(appname, manifest=security_json, override=override_json,
                  additional=additional_json)
        n = "com.ubuntu.developer.username.myapp_%s_0.1.json" % appname
        nbase = n.strip(".json")

        return (c, n, nbase)

    def test_valid_additional1(self):
        '''Test valid additional+override - remove one, add another'''
        sec = '"policy_groups": [ "networking" ]'
        over = '"policy_groups": [ "networking" ]'
        add = '"policy_groups": [ "location" ]'
        (c, n, nbase) = self._stub_keys(sec, over, add)

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 1
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "location")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\nadditional:\n%s" % (expected, count, sec, add))

        expected = 0
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "networking")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\nadditional:\n%s" % (expected, count, sec, add))

    def test_valid_additional2(self):
        '''Test valid additional+override - add existing, remove same'''
        sec = '"policy_groups": [ "networking" ]'
        over = '"policy_groups": [ "networking" ]'
        add = '"policy_groups": [ "networking" ]'
        (c, n, nbase) = self._stub_keys(sec, over, add)

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 0
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "networking")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\nadditional:\n%s" % (expected, count, sec, add))

    def test_valid_additional3(self):
        '''Test valid additional+override - add one, remove added'''
        sec = '"policy_groups": [ ]'
        over = '"policy_groups": [ "networking" ]'
        add = '"policy_groups": [ "networking" ]'
        (c, n, nbase) = self._stub_keys(sec, over, add)

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 0
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "networking")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\nadditional:\n%s" % (expected, count, sec, add))

    def test_valid_additional4(self):
        '''Test valid additional+override - add different, remove different'''
        sec = '"policy_groups": [ "networking" ]'
        over = '"policy_groups": [ "location" ]'
        add = '"policy_groups": [ "location" ]'
        (c, n, nbase) = self._stub_keys(sec, over, add)

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 1
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "networking")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\nadditional:\n%s" % (expected, count, sec, add))

        expected = 0
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "location")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\nadditional:\n%s" % (expected, count, sec, add))

    def test_valid_additional5(self):
        '''Test valid additional+override - add different, remove existing'''
        sec = '"policy_groups": [ "networking" ]'
        over = '"policy_groups": [ "networking" ]'
        add = '"policy_groups": [ "location" ]'
        (c, n, nbase) = self._stub_keys(sec, over, add)

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 0
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "networking")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\nadditional:\n%s" % (expected, count, sec, add))

        expected = 1
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "location")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\nadditional:\n%s" % (expected, count, sec, add))

    def test_valid_additional6(self):
        '''Test valid additional+override - add different, remove multi'''
        sec = '"policy_groups": [ "networking", "location" ]'
        over = '"policy_groups": [ "networking", "location" ]'
        add = '"policy_groups": [ "contacts" ]'
        (c, n, nbase) = self._stub_keys(sec, over, add)

        cm = click.ClickManifest(os.path.join(c.click_dir, n))
        easyprof_manifest = click.transform(cm)

        expected = 0
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "networking")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\nadditional:\n%s" % (expected, count, sec, add))

        expected = 0
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "location")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\nadditional:\n%s" % (expected, count, sec, add))

        expected = 1
        count = easyprof_manifest["profiles"][nbase]["policy_groups"].count(
            "contacts")
        self.assertEquals(expected, count,
                          "Expected to get %d, got %d:\noriginal:\n%s"
                          "\nadditional:\n%s" % (expected, count, sec, add))


class AppArmorPolicyModificationTests(unittest.TestCase):
    def setUp(self):
        self.remove_profiles = []

    def tearDown(self):
        if "ADTTMP" in os.environ:  # skip unload if running under autopkgtest
            return
        apparmor_remove = "/sys/kernel/security/apparmor/.remove"
        for p in self.remove_profiles:
            with open(apparmor_remove, 'w') as f:
                f.write(p)

    def test_load_simple_policy(self):
        '''Test basic load policy function'''
        policy = "profile invalid_policy_dont_use { }"
        with tempfile.NamedTemporaryFile(prefix="aa-clicktest-",
                                         delete=False) as profile:
            profile.write(bytes(policy, 'utf-8'))
            name = profile.name

        try:
            rc, output = click.load_profile(name)
        except:
            raise

        self.remove_profiles.append('invalid_policy_dont_use')
        os.remove(name)

    def test_load_simple_policies(self):
        '''Test basic load policies function'''
        policy = "profile invalid_policy_dont_use { }"
        with tempfile.NamedTemporaryFile(prefix="aa-clicktest-",
                                         delete=False) as profile:
            profile.write(bytes(policy, 'utf-8'))
            name = profile.name

        try:
            rc, output = click.load_profiles([name])
        except:
            raise

        self.remove_profiles.append('invalid_policy_dont_use')
        os.remove(name)

    def test_load_no_policies(self):
        '''Test load zero policies function'''
        try:
            rc, output = click.load_profiles([])
        except:
            raise

    def test_unload_simple_policy(self):
        '''Test unload simple policy'''
        policy = "profile invalid_policy_dont_use { }"
        with tempfile.NamedTemporaryFile(prefix="aa-clicktest-",
                                         delete=False) as profile:
            profile.write(bytes(policy, 'utf-8'))
            name = profile.name

        try:
            rc, output = click.load_profile(name)
        except:
            raise

        click.unload_profile('invalid_policy_dont_use')
        os.remove(name)

    def test_unload_simple_policies(self):
        '''Test unload simple policies'''
        policies = ['more_invalid_policy_%s' % (suffix)
                    for suffix in ['blart', 'blort', 'blat']]
        names = []
        for p in policies:
            policy = "profile %s { }" % (p)
            with tempfile.NamedTemporaryFile(prefix="aa-clicktest-",
                                             delete=False) as profile:
                profile.write(bytes(policy, 'utf-8'))
                names.append(profile.name)

        try:
            rc, output = click.load_profiles(names)
        except:
            raise

        click.unload_profiles(policies)
        for name in names:
            os.remove(name)

    def test_unload_nonexistent_policy(self):
        '''Test unload nonexistent policy'''
        profile = 'invalid_policy_does_not_exist_dont_use'
        click.unload_profile(profile)

    def test_apparmor_available(self):
        '''Test apparmor_available()'''
        try:
            click.apparmor_available(parser="./aa-clickhook",
                                     apparmor_dirs=['./'])
        except AppArmorException:
            raise Exception("apparmor_available() should have passed")

    def test_apparmor_not_available(self):
        '''Test apparmor not available'''
        try:
            click.apparmor_available(parser="/nonexistent",
                                     apparmor_dirs=['/nonexistent.dir'])
        except AppArmorException as e:
            self.assertTrue("Could not find '/nonexistent.dir'" in str(e))
            return
        except Exception:
            raise
        raise Exception("apparmor_available should have failed")


class AppArmorRawProfileTransform(unittest.TestCase):
    def setUp(self):
        self.tmpdir = tempfile.mkdtemp(prefix="aa-click-profile-")
        self.clickstate = ClickState(self.tmpdir)
        self.maxDiff = None

    def tearDown(self):
        if os.path.exists(self.tmpdir):
            shutil.rmtree(self.tmpdir)

    def test_profile_transform(self):
        '''Test profile transform'''
        c = self.clickstate

        name = "com.ubuntu.developer.username.myapp"
        appname = "sample-app"
        version = "0.1"

        p = "%s_%s_%s" % (name, appname, version)

        c.add_package(name, version)
        c.add_app(appname, aa_profile=self.clickstate._get_profile())

        fin = os.path.join(self.clickstate.click_dir, "%s.profile" % (p))
        fout = os.path.join(self.clickstate.profiles_dir, "profile_%s" % (p))
        click._raw_transform(fin, fout)

        with open(fout, 'r') as f:
            contents = f.read()
            f.close()

        expected = self.clickstate._get_profile()
        var = '''@{CLICK_DIR}="%s"
@{APP_PKGNAME}="%s"
@{APP_APPNAME}="%s"
@{APP_VERSION}="%s"''' % (click_databases, name, appname, version)
        expected = re.sub(r'###VAR###',
                          var,
                          expected)
        expected = re.sub(r'###PROFILEATTACH###',
                          'profile "%s"' % p,
                          expected)

        self.assertEquals(expected, contents,
                          "Expected %s and %s to be the same" %
                          (expected, contents))

    def test_profile_transform_noext(self):
        '''Test profile transform (without .profile)'''
        c = self.clickstate

        name = "com.ubuntu.developer.username.myapp"
        appname = "sample-app"
        version = "0.1"

        p = "%s_%s_%s" % (name, appname, version)

        c.add_package(name, version)
        c.add_app(appname, aa_profile=self.clickstate._get_profile())

        fin = os.path.join(self.clickstate.click_dir, "%s" % (p))
        os.rename("%s.profile" % fin, fin)
        fout = os.path.join(self.clickstate.profiles_dir, "profile_%s" % (p))
        click._raw_transform(fin, fout)

        with open(fout, 'r') as f:
            contents = f.read()
            f.close()

        expected = self.clickstate._get_profile()
        var = '''@{CLICK_DIR}="%s"
@{APP_PKGNAME}="%s"
@{APP_APPNAME}="%s"
@{APP_VERSION}="%s"''' % (click_databases, name, appname, version)
        expected = re.sub(r'###VAR###',
                          var,
                          expected)
        expected = re.sub(r'###PROFILEATTACH###',
                          'profile "%s"' % p,
                          expected)

        self.assertEquals(expected, contents,
                          "Expected %s and %s to be the same" %
                          (expected, contents))

    def test_profile_transform_badfilename(self):
        '''Test profile transform'''
        c = self.clickstate

        name = "com.ubuntu.developer.username.myapp"
        appname = "sample-app"
        version = "0.1"

        p = "%s_%s_%s" % (name, appname, version)

        c.add_package(name, version)
        c.add_app(appname, aa_profile=self.clickstate._get_profile())

        fin = os.path.join(self.clickstate.click_dir, "%s.profile" % (p))
        badfin = os.path.join(self.clickstate.click_dir,
                              "badformat_%s.profile" % (p))
        os.rename(fin, badfin)
        fout = os.path.join(self.clickstate.profiles_dir, "profile_%s" % (p))

        try:
            click._raw_transform(badfin, fout)
        except AppArmorException:
            return
        except Exception:
            raise
        raise Exception("name %s should be invalid" % (badfin))


class AppArmorProfileSynchronization(unittest.TestCase):
    def setUp(self):
        self.tmpdir = tempfile.mkdtemp(prefix="aa-click-profile-")
        self.clickstate = ClickState(self.tmpdir)
        self.maxDiff = None

    def tearDown(self):
        if os.path.exists(self.tmpdir):
            shutil.rmtree(self.tmpdir)

    def test_find_profile_file(self):
        '''Test being given a symlink and finding the package profile'''
        c = self.clickstate
        c.add_package("package", "version")
        c.add_app("app", aa_profile=self.clickstate._get_profile())

        (result, pkg_dir) = click.get_package_manifest(
            os.path.join(c.click_dir, "package_app_version.profile"),
            "package")
        self.assertEquals(c.click_manifest, result,
                          "Expected to get %s, got %s" %
                          (c.click_manifest, result))
        self.assertEquals(c.pkg_dir, pkg_dir, "Expected to get %s, got %s" %
                                              (c.pkg_dir, pkg_dir))

    def test_two_equal_directories(self):
        '''Test two equal directories'''
        c = self.clickstate

        clicks = ["alpha_beta_gamma", "click_click_version",
                  "wat_no-really_wat"]
        for cname in clicks:
            with open(os.path.join(c.click_dir, '%s' %
                      (cname)), 'w+') as f:
                f.write('invalid profile here')
            with open(os.path.join(c.profiles_dir, 'profile_%s' %
                                   (cname)), 'w+') as f:
                f.write('profile %s { }' % (cname))

        expected = []
        result = click.get_missing_raw_profiles(c.click_dir, c.profiles_dir)
        self.assertEquals(expected, result,
                          "Expected to get no profiles, got %s" % (result))
        result = click.get_missing_rawhooks(c.click_dir, c.profiles_dir)
        self.assertEquals(expected, result,
                          "Expected to get no raw hooks, got %s" % (result))

    def test_two_empty_directories_for_profiles(self):
        '''Test two empty directories returns no new needed profiles'''
        c = self.clickstate

        expected = []
        result = click.get_missing_raw_profiles(c.click_dir, c.profiles_dir)
        self.assertEquals(expected, result,
                          "Expected to get no profiles, got %s" % (result))

    def test_two_empty_directories_for_clicks(self):
        '''Test two empty directories returns no removed raw hooks'''
        c = self.clickstate

        expected = []
        result = click.get_missing_rawhooks(c.click_dir, c.profiles_dir)
        self.assertEquals(expected, result,
                          "Expected to get no raw hooks, got %s" % (result))

    def test_versus_empty_profiles_directory(self):
        '''Test against empty profiles directory'''
        c = self.clickstate
        clicks = ["alpha_beta_gamma.profile", "click_click_version.profile",
                  "wat_no-really_wat.profile"]
        for cname in clicks:
            with open(os.path.join(c.click_dir, cname), 'w+') as f:
                f.write('invalid profile here')

        expected = set(clicks)
        result = set(click.get_missing_raw_profiles(c.click_dir,
                     c.profiles_dir))
        self.assertEquals(expected, result,
                          "Expected to get %s profiles, got %s" % (expected,
                                                                   result))

    def test_versus_empty_clicks_directory(self):
        '''Test against empty clicks directory'''
        c = self.clickstate
        clicks = ["alpha_beta_gamma", "click_click_version",
                  "wat_no-really_wat"]
        for cname in clicks:
            with open(os.path.join(c.profiles_dir, 'profile_%s' %
                                   (cname)), 'w+') as f:
                f.write('profile %s { }' % (cname))

        expected = set(["%s%s" % ("profile_", x)
                       for x in clicks])
        result = set(click.get_missing_rawhooks(c.click_dir, c.profiles_dir))
        self.assertEquals(expected, result,
                          "Expected to get %s hooks, got %s" % (expected,
                                                                result))

    def test_two_unequal_directories(self):
        '''Test two unequal directories'''
        c = self.clickstate
        expected_clicks = ['missing_click_profile',
                           'another-missing_click_profile']
        expected_profiles = ['%sremoved_click_package' %
                             ("profile_")]
        clicks = ["alpha_beta_gamma", "click_click_version",
                  "wat_no-really_wat"]
        profiles = ["%s%s" % ("profile_", x) for x in clicks]
        clicks.extend(expected_clicks)
        profiles.extend(expected_profiles)
        for cname in clicks:
            with open(os.path.join(c.click_dir, cname), 'w+') as f:
                f.write('invalid profile here')
        for pname in profiles:
            with open(os.path.join(c.profiles_dir, pname), 'w+') as f:
                f.write('profile %s { }' % (pname))

        result = set(click.get_missing_raw_profiles(c.click_dir,
                     c.profiles_dir))
        self.assertEquals(set(expected_clicks), result,
                          "Expected to get '%s' missing profiles, got %s" %
                          (set(expected_clicks), result))
        result = set(click.get_missing_rawhooks(c.click_dir, c.profiles_dir))
        self.assertEquals(set(expected_profiles), result,
                          "Expected to get '%s' missing raw hooks, got %s" %
                          (set(expected_profiles), result))

    def test_two_unequal_directories_bad_profile_filename(self):
        '''Test two unequal directories (bad profile_filename)'''
        c = self.clickstate
        clicks = ["alpha_beta_gamma", "click_click_version",
                  "wat_no-really_wat"]
        for cname in clicks:
            with open(os.path.join(c.click_dir, '%s' %
                      (cname)), 'w+') as f:
                f.write('invalid profile here')
            with open(os.path.join(c.profiles_dir, 'badformat_%s' %
                                   (cname)), 'w+') as f:
                f.write('profile %s { }' % (cname))

        expected = []
        result = click.get_missing_rawhooks(c.click_dir, c.profiles_dir)
        self.assertEquals(expected, result,
                          "Expected to get no raw hooks, got %s" % (result))

    def test_two_equal_directories_new_symlink(self):
        '''Test two equal directories with new symlink (LP: #1291549)'''
        c = self.clickstate
        clicks = ["alpha_beta_gamma", "click_click_version",
                  "wat_no-really_wat"]
        for cname in clicks:
            with open(os.path.join(c.click_dir, '%s' %
                      (cname)), 'w+') as f:
                f.write('invalid profile here')
            with open(os.path.join(c.profiles_dir, 'profile_%s' %
                                   (cname)), 'w+') as f:
                f.write('profile %s { }' % (cname))

        # Click hooks not updated yet, so everything should be the same
        expected = []
        result = click.get_missing_raw_profiles(c.click_dir, c.profiles_dir)
        self.assertEquals(expected, result,
                          "Expected to get no profiles, got %s" % (result))
        result = click.get_missing_rawhooks(c.click_dir, c.profiles_dir)
        self.assertEquals(expected, result,
                          "Expected to get no raw hooks, got %s" % (result))

        time.sleep(1)
        clicks = ["alpha_beta_gamma", "click_click_version"]
        for cname in clicks:
            with open(os.path.join(c.click_dir, '%s' %
                      (cname)), 'w+') as f:
                f.write('invalid profile here')

        expected = []
        result = click.get_missing_rawhooks(c.click_dir, c.profiles_dir)
        self.assertEquals(expected, result,
                          "Expected to get no raw hooks, got %s" % (result))
        expected = len(clicks)
        result = click.get_missing_raw_profiles(c.click_dir, c.profiles_dir)
        self.assertEquals(expected, len(result),
                          "Expected to get %d profiles, got %s:\n" %
                          (expected, len(result)))


if __name__ == '__main__':
    suite = unittest.TestSuite()
    suite.addTest(unittest.TestLoader().loadTestsFromTestCase(T))
    if os.geteuid() == 0:
        suite.addTest(unittest.TestLoader().loadTestsFromTestCase(
                      AppArmorPolicyModificationTests))
    else:
        print('Not running as root, skipping tests that load/unload ' +
              'AppArmor policy', file=sys.stderr)
    suite.addTest(unittest.TestLoader().loadTestsFromTestCase(
                  AppArmorManifestSynchronization))
    suite.addTest(unittest.TestLoader().loadTestsFromTestCase(
                  AppArmorRawProfileTransform))
    suite.addTest(unittest.TestLoader().loadTestsFromTestCase(
                  AppArmorProfileSynchronization))
    suite.addTest(unittest.TestLoader().loadTestsFromTestCase(
                  AppArmorManifestOverride))
    suite.addTest(unittest.TestLoader().loadTestsFromTestCase(
                  AppArmorManifestAdditional))
    suite.addTest(unittest.TestLoader().loadTestsFromTestCase(
                  AppArmorManifestAdditionalWithOverride))

    rc = unittest.TextTestRunner(verbosity=2).run(suite)

    if not rc.wasSuccessful():
        sys.exit(1)
