#!/usr/bin/python -tt
# vim: ai ts=4 sts=4 et sw=4
#
# Copyright (C) 2010, 2011, 2012, 2013, 2014 Intel, Inc.
#
#    This program is free software; you can redistribute it and/or
#    modify it under the terms of the GNU General Public License
#    as published by the Free Software Foundation; version 2 of the License.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#

"""Unit tests for RepoMaker"""

import os
import unittest
import tempfile
import shutil
import contextlib
import base64
import glob
import gzip

from xml.dom import minidom

from common.repomaker import RepoMaker, RepoMakerError

# rpm content
RPM = base64.b64decode("""7avu2wMAAAEAAXBrZzEtMS4wLTEAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAUAAAAAAAAAAAAAAAAAAAAA
jq3oAQAAAAAAAAAFAAAAVAAAAD4AAAAHAAAARAAAABAAAAPoAAAABAAAAAAAAAABAAAD7AAAAAcA
AAAEAAAAEAAAAQ0AAAAGAAAAFAAAAAEAAAPvAAAABAAAAEAAAAABAAAGAZifaNg82W1fAFmktnky
lPk5ZjRlY2QzYjdlNmY2MjRjZDQyMzEwYTdiNzAwYjllZWQyM2E0NzMwAAAAAAAAAywAAAA+AAAA
B////7AAAAAQAAAAAI6t6AEAAAAAAAAAKgAAAXkAAAA/AAAABwAAAWkAAAAQAAAAZAAAAAgAAAAA
AAAAAQAAA+gAAAAGAAAAAgAAAAEAAAPpAAAABgAAAAcAAAABAAAD6gAAAAYAAAALAAAAAQAAA+wA
AAAJAAAADQAAAAEAAAPtAAAA
CQAAACUAAAABAAAD7gAAAAQAAABQAAAAAQAAA+8AAAAGAAAAVAAAAAEAAAPxAAAABAAAAFgAAAAB
AAAD9gAAAAYAAABcAAAAAQAAA/gAAAAJAAAAYgAAAAEAAAP8AAAABgAAAHoAAAABAAAD/QAAAAYA
AACOAAAAAQAAA/4AAAAGAAAAlAAAAAEAAAQEAAAABAAAAJwAAAABAAAEBgAAAAMAAACgAAAAAQAA
BAkAAAADAAAAogAAAAEAAAQKAAAABAAAAKQAAAABAAAECwAAAAgAAACoAAAAAQAABAwAAAAIAAAA
yQAAAAEAAAQNAAAABAAAAMwAAAABAAAEDwAAAAgAAADQAAAAAQAABBAAAAAIAAAA1QAAAAEAAAQV
AAAABAAAANwAAAABAAAEGAAAAAQAAADgAAAAAQAABBkAAAAIAAAA5AAAAAEAAAQaAAAACAAAAQAA
AAABAAAEKAAAAAYAAAEIAAAAAQAABDgAAAAEAAABEAAAAAEAAAQ5AAAACAAAARQAAAABAAAEOgAA
AAgAAAEtAAAAAQAABEcAAAAEAAABNAAAAAEAAARIAAAABAAAATgAAAABAAAESQAAAAgAAAE8AAAA
AQAABFwAAAAEAAABQAAAAAEAAARdAAAACAAAAUQAAAABAAAEXgAAAAgAAAFOAAAAAQAABGQAAAAG
AAABTwAAAAEAAARlAAAABgAAAVQAAAABAAAEZgAAAAYAAAFZAAAAAQAABEYAAAAGAAABWwAAAAFD
AHBrZzEAMS4wADEAVGVzdGluZyBtaW5pbWFsIHBhY2thZ2UATWluaW1hbCBycG0gcGFja2FnZSBm
b3IgdGVzdGluZyBwdXJwb3Nlcy4AAFGNBQtlZAAAAAACN0dQTHYyAERldmVsb3BtZW50L1Rvb2xz
L090aGVyAGh0dHA6Ly9mYWtlLmNvbS9ibGEAbGludXgAaTU4NgAAAAAAAAI3gaQAAFGNBQg0M2Rm
ZDI1ZmZmNWVjNTU0MDVmOTBhNjlhNmI4NjI1ZQAAAAAAAAAgcm9vdAByb290AAAA/////wEAAApy
cG1saWIoQ29tcHJlc3NlZEZpbGVOYW1lcykAMy4wLjQtMQA0LjkuMS4yAFGM4UBlZHVhcmQuYmFy
dG9zaEBpbnRlbC5jb20ALSBJbml0AAAACAEAEUgfAAAAAAAAAABwa2cxLnNwZWMAAGNwaW8AZ3pp
cAA5AGVkIDEzNjgxOTYzNjMAAAAAPwAAAAf///1gAAAAEB+LCAAAAAAAAgONUmFv2jAQ5Wv9K45u
SDA1iU2LQBRV20TbIcGoMrqvyDhOsHBsy3YqVYj/PsOStps2qe+Dfb737s56Nh7iISYYE3I1IjkO
GBF6hf8NMiCjDA/w6HTqXw7r/Kjh/1NHm8DsChI7w1nrOy35GF5xZNBPbp3Q6iVPYoxSLjl1r1qC
flRlSe3zS2bFnReqgFIoUVIJhrIdLTiaC8bVm8r7h/lTH91bXZnx2dmUP3GpTcmVT1ZaS5cs/ZZb
9JjOA7v13oyTJKc7HjNdJhtJEepk3DErjA93RIt6mjVlMxFybcHXtzGVNdpxF4c6Y7lBXUY9TCa3
yzv0QSgmq4zDxPlM6Hh7g4TyUFKhuj3Yo5MhNqTy7vk3LqW+gM5eBccO7fPe9Ym23FdWAb5GB3Rs
2YObRhOzMHJTCZmhgjGIdEP8IRDKeSolqneIphCVeDgYnJ4CPu7Th8X66+NsPl2ny+XqkFTOJhuh
krpJaJELyd3RlZx6b7vRhdXa/16iHurs10GeCXt4U8K2VBXB9wKhT3BnBSzoMxAMfUwuIQKeVdRm
8YZar932c3CAy6P/KIKZEh5QC9f/9V14r+5vbJpglX6ZzW/TdrvdCvgF1lylJCwDAAA=""")

@contextlib.contextmanager
def tempdir(suffix='', prefix='tmp'):
    """
    A context manager for creating and then
    deleting a temporary directory.
    """
    tmpdir = tempfile.mkdtemp(prefix=prefix, suffix=suffix)
    try:
        yield tmpdir
    finally:
        shutil.rmtree(tmpdir)

def prepare_dir(in_repo, arches):
    """Create test directory structure."""
    files = ["%s-%s.%s.rpm" % (name, version, arch) \
             for name in ("pkg1", "pkg2", "pkg3") \
             for version in ("0.1-2.3", "1.2-3.4") \
             for arch in arches]
    for fname in files:
        subdir = fname.split('.')[-2]
        #subdir = ('', fname)[files.index(fname) % 2]
        dir_path = os.path.join(in_repo, subdir)
        if not os.path.exists(dir_path):
            os.makedirs(dir_path)
        with open(os.path.join(dir_path, fname), 'w') as frpm:
            frpm.write(RPM)


class RepoMakerTest(unittest.TestCase):
    '''Tests for RepoMaker functionality.'''

    def test_non_existing_dir(self):
        """Test exception raised when output dir doesn't exist."""
        maker = RepoMaker('test-id', 'outrepo')
        self.assertRaises(RepoMakerError, maker.add_repo,
                           'aj45sdjfoqwiq4334w', 'test-repo')

    def test_add_repo(self):
        """Test converting repository to the download structure."""
        with tempdir(prefix='repomaker.', suffix='.inrepo') as in_repo:
            prepare_dir(in_repo + '/testrepo', ['src', 'noarch', 'i586', 'i686', 'x86_64',
                                  'armv7el'])
            with tempdir(prefix='repomaker.', suffix='.outrepo') as out_repo:
                out_repo = "/tmp/out_rep"
                maker = RepoMaker('test-id', out_repo)
                maker.add_repo(in_repo, 'testrepo', ('ia32', 'x86_64'),
                               move=True, gpg_key='key', signer='/bin/true',
                               buildconf='buildconf')
                # Check repo structure
                results = {
                    'source':
                        ['pkg1-0.1-2.3.src.rpm', 'pkg1-1.2-3.4.src.rpm',
                         'pkg2-0.1-2.3.src.rpm', 'pkg2-1.2-3.4.src.rpm',
                         'pkg3-0.1-2.3.src.rpm', 'pkg3-1.2-3.4.src.rpm'],
                    'packages':
                        ['i586/pkg1-0.1-2.3.i586.rpm',
                         'i586/pkg1-1.2-3.4.i586.rpm',
                         'i586/pkg2-0.1-2.3.i586.rpm',
                         'i586/pkg2-1.2-3.4.i586.rpm',
                         'i586/pkg3-0.1-2.3.i586.rpm',
                         'i586/pkg3-1.2-3.4.i586.rpm',
                         'i686/pkg1-0.1-2.3.i686.rpm',
                         'i686/pkg1-1.2-3.4.i686.rpm',
                         'i686/pkg2-0.1-2.3.i686.rpm',
                         'i686/pkg2-1.2-3.4.i686.rpm',
                         'i686/pkg3-0.1-2.3.i686.rpm',
                         'i686/pkg3-1.2-3.4.i686.rpm',
                         'noarch/pkg1-0.1-2.3.noarch.rpm',
                         'noarch/pkg1-1.2-3.4.noarch.rpm',
                         'noarch/pkg2-0.1-2.3.noarch.rpm',
                         'noarch/pkg2-1.2-3.4.noarch.rpm',
                         'noarch/pkg3-0.1-2.3.noarch.rpm',
                         'noarch/pkg3-1.2-3.4.noarch.rpm',
                         'x86_64/pkg1-0.1-2.3.x86_64.rpm',
                         'x86_64/pkg1-1.2-3.4.x86_64.rpm',
                         'x86_64/pkg2-0.1-2.3.x86_64.rpm',
                         'x86_64/pkg2-1.2-3.4.x86_64.rpm',
                         'x86_64/pkg3-0.1-2.3.x86_64.rpm',
                         'x86_64/pkg3-1.2-3.4.x86_64.rpm'],
                    'debug': []
                }

                baserepo = os.path.join(out_repo, 'repos', 'testrepo')
                # Make sure that not interesting arch armv7el has been skipped
                gen_dirs = sorted(os.path.basename(path) \
                        for path in glob.glob(os.path.join(baserepo, '*')))
                self.assertEqual(gen_dirs, ['debug', 'packages', 'source'])

                # test if all packages are present in primary.xml
                for arch in ('source', 'packages', 'debug'):
                    primary_path = glob.glob(os.path.join(baserepo, arch,
                                                          'repodata',
                                                          '*primary.xml.gz'))[0]
                    dom = minidom.parse(gzip.open(primary_path))
                    packages = sorted(elem.getAttribute('href') for elem in \
                                          dom.getElementsByTagName('location'))
                    self.assertEqual(packages, results[arch])

    def test_add_repo_noarch(self):
        """
        Test converting repository to the download structure.
        Input repo contains only noarch packages.
        """
        with tempdir(prefix='repomaker.', suffix='.inrepo') as in_repo:
            prepare_dir(in_repo + '/testrepo-noarch', ['src', 'noarch'])

            with tempdir(prefix='repomaker.', suffix='.outrepo') as out_repo:
                maker = RepoMaker('test-id', out_repo)
                maker.add_repo(in_repo, 'testrepo-noarch', ('ia32', 'x86_64'),
                               move=True, gpg_key='key', signer='/bin/true',
                               buildconf='buildconf')
                # Check repo structure
                results = {
                    'source':
                        ['pkg1-0.1-2.3.src.rpm', 'pkg1-1.2-3.4.src.rpm',
                         'pkg2-0.1-2.3.src.rpm', 'pkg2-1.2-3.4.src.rpm',
                         'pkg3-0.1-2.3.src.rpm', 'pkg3-1.2-3.4.src.rpm'],
                    'packages':
                        ['noarch/pkg1-0.1-2.3.noarch.rpm',
                         'noarch/pkg1-1.2-3.4.noarch.rpm',
                         'noarch/pkg2-0.1-2.3.noarch.rpm',
                         'noarch/pkg2-1.2-3.4.noarch.rpm',
                         'noarch/pkg3-0.1-2.3.noarch.rpm',
                         'noarch/pkg3-1.2-3.4.noarch.rpm'],
                    'debug': []
                }

                for arch in ('source', 'debug', 'packages'):
                    primary_path = glob.glob(os.path.join(out_repo,
                                                          'repos',
                                                          'testrepo-noarch',
                                                          arch,
                                                          'repodata',
                                                          '*primary.xml.gz'))[0]

                    #print 'primary_path=', primary_path
                    dom = minidom.parse(gzip.open(primary_path))
                    packages = sorted(elem.getAttribute('href') for elem in \
                                          dom.getElementsByTagName('location'))
                    self.assertEqual(packages, results[arch])
