Example #1
0
    def test_one_file_svn_lines_changed(self):
        b = DNSBuilder(STAGE_DIR=self.stage_dir, PROD_DIR=self.prod_dir,
                       LOCK_FILE=self.lock_file, LOG_SYSLOG=False,
                       FIRST_RUN=True, PUSH_TO_PROD=False,
                       STOP_UPDATE_FILE=self.stop_update_file)
        test_file = os.path.join(self.prod_dir, 'test')
        with open(test_file, 'w+') as fd:
            fd.write('line 1\n')
        lc = b.svn_lines_changed(b.PROD_DIR)
        self.assertEqual((1, 0), lc)
        b.svn_checkin(lc)

        with open(test_file, 'w+') as fd:
            fd.write('line 1\nline 2\n')

        lc = b.svn_lines_changed(b.PROD_DIR)
        self.assertEqual((1, 0), lc)
        b.svn_checkin(lc)

        with open(test_file, 'w+') as fd:
            fd.write('line 1\n')

        lc = b.svn_lines_changed(b.PROD_DIR)
        self.assertEqual((0, 1), lc)
        b.svn_checkin(lc)
Example #2
0
 def test_stop_update(self):
     if os.path.exists(self.stop_update):
         os.remove(self.stop_update)
     b = DNSBuilder(STAGE_DIR=self.stage_dir,
                    PROD_DIR=self.prod_dir,
                    LOCK_FILE=self.lock_file,
                    STOP_UPDATE_FILE=self.stop_update)
     open(self.stop_update, 'w+').close()
     try:
         self.assertTrue(b.stop_update_exists())
     finally:
         os.remove(self.stop_update)
Example #3
0
 def test_stop_update(self):
     if os.path.exists(self.stop_update):
         os.remove(self.stop_update)
     b = DNSBuilder(
         STAGE_DIR=self.stage_dir,
         PROD_DIR=self.prod_dir,
         LOCK_FILE=self.lock_file,
         STOP_UPDATE_FILE=self.stop_update,
     )
     open(self.stop_update, "w+").close()
     try:
         self.assertTrue(b.stop_update_exists())
     finally:
         os.remove(self.stop_update)
Example #4
0
 def test_build_zone(self):
     create_fake_zone('asdf1')
     b = DNSBuilder(STAGE_DIR=self.stage_dir, PROD_DIR=self.prod_dir,
                    LOCK_FILE=self.lock_file, LOG_SYSLOG=False,
                    FIRST_RUN=True, PUSH_TO_PROD=False,
                    STOP_UPDATE_FILE=self.stop_update_file)
     b.build_dns()
     create_fake_zone('asdf2')
     b.build_dns()
     create_fake_zone('asdf3')
     create_fake_zone('asdf4')
     b.build_dns()
     create_fake_zone('asdf5')
     b.build_dns()
Example #5
0
def main():
    parser = argparse.ArgumentParser(description="DNS Build scripts")
    parser.add_argument(
        "--stage-only",
        dest="STAGE_ONLY",
        action="store_true",
        default=False,
        help="Just build staging and don't " "copy to prod. named-checkzone will still be run.",
    )
    parser.add_argument(
        "--clobber-stage",
        dest="CLOBBER_STAGE",
        action="store_true",
        default=False,
        help="If stage " "already exists delete it before running the build " "script.",
    )
    parser.add_argument(
        "--ship-it",
        dest="PUSH_TO_PROD",
        action="store_true",
        default=False,
        help="Check files " "into rcs and push upstream.",
    )
    parser.add_argument(
        "--preserve-stage",
        dest="PRESERVE_STAGE",
        action="store_true",
        default=False,
        help="Do not " "remove staging area after build completes.",
    )
    parser.add_argument(
        "--no-build", dest="BUILD_ZONES", action="store_false", default=True, help="Do not " "build zone files."
    )
    parser.add_argument(
        "--no-syslog", dest="LOG_SYSLOG", action="store_false", default=True, help="Do not " "log to syslog."
    )
    parser.add_argument(
        "--debug", dest="DEBUG", action="store_true", default=False, help="Print " "copious amounts of text."
    )
    parser.add_argument(
        "--first-run",
        dest="FIRST_RUN",
        action="store_true",
        default=False,
        help="Ignore " "all change delta thresholds.",
    )
    nas = parser.parse_args(sys.argv[1:])
    b = DNSBuilder(**dict(nas._get_kwargs()))
    try:
        b.build_dns()
    except BuildError as why:
        b.log("LOG_ERR", why)
        # fail_mail(message.format(why))
    except Exception as err:
        # Make some noise
        # fail_mail(message.format(err))
        b.log("LOG_CRIT", err)
        raise
Example #6
0
    def test_build_staging(self):
        if os.path.isdir(self.stage_dir):
            shutil.rmtree(self.stage_dir)
        b = DNSBuilder(STAGE_DIR=self.stage_dir,
                       PROD_DIR=self.prod_dir,
                       LOCK_FILE=self.lock_file)
        b.build_staging()
        # Make sure it made the staging dir
        self.assertTrue(os.path.isdir(self.stage_dir))
        # Ensure if fails if the directory exists
        self.assertRaises(BuildError, b.build_staging)
        # There shouldn't be errors because force=True
        b.build_staging(force=True)

        self.assertTrue(os.path.isdir(self.stage_dir))
        b.clear_staging()
        self.assertFalse(os.path.isdir(self.stage_dir))
        self.assertRaises(BuildError, b.clear_staging)
        b.clear_staging(force=True)
        self.assertFalse(os.path.isdir(self.stage_dir))
Example #7
0
    def test_build_staging(self):
        if os.path.isdir(self.stage_dir):
            shutil.rmtree(self.stage_dir)
        b = DNSBuilder(STAGE_DIR=self.stage_dir, PROD_DIR=self.prod_dir, LOCK_FILE=self.lock_file)
        b.build_staging()
        # Make sure it made the staging dir
        self.assertTrue(os.path.isdir(self.stage_dir))
        # Ensure if fails if the directory exists
        self.assertRaises(BuildError, b.build_staging)
        # There shouldn't be errors because force=True
        b.build_staging(force=True)

        self.assertTrue(os.path.isdir(self.stage_dir))
        b.clear_staging()
        self.assertFalse(os.path.isdir(self.stage_dir))
        self.assertRaises(BuildError, b.clear_staging)
        b.clear_staging(force=True)
        self.assertFalse(os.path.isdir(self.stage_dir))
Example #8
0
    def setUp(self):
        if not os.path.isdir(BINDBUILD['stage_dir']):
            os.makedirs(BINDBUILD['stage_dir'])

        if not os.path.isdir(BINDBUILD['prod_dir']):
            os.makedirs(BINDBUILD['prod_dir'])
        remove_dir_contents(BINDBUILD['prod_dir'])

        if not os.path.isdir(PROD_ORIGIN_DIR):
            os.makedirs(PROD_ORIGIN_DIR)
        remove_dir_contents(PROD_ORIGIN_DIR)

        mgr = GitRepoManager(debug=False, log_syslog=False, config={
            'user.name': 'test',
            'user.email': 'test',
        })
        mgr.init(PROD_ORIGIN_DIR, bare=True)
        mgr.clone(PROD_ORIGIN_DIR, BINDBUILD['prod_dir'])

        self.builder = DNSBuilder(verbose=False, debug=False, **BINDBUILD)
        self.builder.repo.commit_and_push(empty=True, message='Initial commit')

        super(DNSBuildTest, self).setUp()
Example #9
0
 def test_build_svn(self):
     print "This will take a while, be patient..."
     b = DNSBuilder(STAGE_DIR=self.stage_dir,
                    PROD_DIR=self.prod_dir,
                    LOCK_FILE=self.lock_file,
                    LOG_SYSLOG=False,
                    FIRST_RUN=True,
                    PUSH_TO_PROD=True)
     b.build_dns()
     #self.svn_info()
     s = SOA.objects.all()
     if len(s) > 0:
         s[0].dirty = True
         s[0].save()
     b.build_dns()
     #self.svn_info()
     b.build_dns()
Example #10
0
    def handle(self, *args, **options):
        builder_opts = {}

        if options['to_syslog']:
            syslog.openlog('bindbuild', facility=syslog.LOG_LOCAL6)
            builder_opts['to_syslog'] = True

        verbosity = int(options['verbosity'])
        builder_opts['quiet'] = verbosity == 0
        builder_opts['verbose'] = verbosity >= 2

        with DNSBuilder(**builder_opts) as b:
            b.build(force=options['force_build'])
            if options['push']:
                b.push(sanity_check=options['sanity_check'])
Example #11
0
def build_dns():
    args = {
        'FIRST_RUN': False,
        'PRESERVE_STAGE': False,
        'PUSH_TO_PROD': False,
        'BUILD_ZONES': True,
        'LOG_SYSLOG': True,
        'CLOBBER_STAGE': True,
        'STAGE_ONLY': False,
        'DEBUG': False
    }
    b = DNSBuilder(**args)

    try:
        b.build_dns()
    except BuildError as why:
        b.log('LOG_ERR', why)
    except Exception as err:
        b.log('LOG_CRIT', err)
        raise
Example #12
0
    def handle(self, *args, **options):
        builder_opts = {}
        for name in ('log_syslog',):
            val = options.pop(name)
            if val is not None:  # user specified value
                builder_opts[name] = val
            # else get value from settings

        if options['verbosity']:
            builder_opts['verbose'] = int(options['verbosity']) >= 1
            builder_opts['debug'] = int(options['verbosity']) >= 2
        else:
            builder_opts['verbose'] = True
            builder_opts['debug'] = False

        with DNSBuilder(**builder_opts) as b:
            b.build(force=options['force_build'])
            if options['push']:
                b.push(sanity_check=options['sanity_check'])
Example #13
0
 def test_build_svn(self):
     print "This will take a while, be patient..."
     b = DNSBuilder(
         STAGE_DIR=self.stage_dir,
         PROD_DIR=self.prod_dir,
         LOCK_FILE=self.lock_file,
         LOG_SYSLOG=False,
         FIRST_RUN=True,
         PUSH_TO_PROD=True,
     )
     b.build_dns()
     # self.svn_info()
     s = SOA.objects.all()
     if len(s) > 0:
         s[0].dirty = True
         s[0].save()
     b.build_dns()
     # self.svn_info()
     b.build_dns()
Example #14
0
def build_dns():
    args = {'FIRST_RUN': False,
            'PRESERVE_STAGE': False,
            'PUSH_TO_PROD': False,
            'BUILD_ZONES': True,
            'LOG_SYSLOG': True,
            'CLOBBER_STAGE': True,
            'STAGE_ONLY': False,
            'DEBUG': False
            }
    b = DNSBuilder(**args)

    try:
        b.build_dns()
    except BuildError as why:
        b.log(why, 'LOG_ERR')
    except Exception as err:
        b.log(err, 'LOG_CRIT')
        raise
Example #15
0
    def test_too_many_config_lines_changed(self):
        create_fake_zone('asdf86')
        root_domain1 = create_fake_zone('asdf87')
        root_domain2 = create_fake_zone('asdf88')
        root_domain3 = create_fake_zone('asdf89')
        b = DNSBuilder(STAGE_DIR=self.stage_dir, PROD_DIR=self.prod_dir,
                       LOCK_FILE=self.lock_file, LOG_SYSLOG=False,
                       FIRST_RUN=True, PUSH_TO_PROD=True,
                       STOP_UPDATE_FILE=self.stop_update_file)
        b.build_dns()
        for ns in root_domain1.nameserver_set.all():
            ns.delete()

        b.build_dns()  # One zone removed should be okay

        for ns in root_domain2.nameserver_set.all():
            ns.delete()

        for ns in root_domain3.nameserver_set.all():
            ns.delete()

        self.assertRaises(BuildError, b.build_dns)
Example #16
0
    def test_lock_unlock(self):
        if os.path.exists(self.lock_file):
            os.remove(self.lock_file)
        b1 = DNSBuilder(STAGE_DIR=self.stage_dir,
                        PROD_DIR=self.prod_dir,
                        LOCK_FILE=self.lock_file)
        b2 = DNSBuilder(STAGE_DIR=self.stage_dir,
                        PROD_DIR=self.prod_dir,
                        LOCK_FILE=self.lock_file)
        b3 = DNSBuilder(STAGE_DIR=self.stage_dir,
                        PROD_DIR=self.prod_dir,
                        LOCK_FILE=self.lock_file)
        self.assertFalse(os.path.exists(self.lock_file))
        self.assertTrue(b1.lock())
        self.assertTrue(os.path.exists(self.lock_file))
        self.assertTrue(b1.unlock())

        self.assertTrue(b1.lock())
        self.assertFalse(b2.lock())
        self.assertFalse(b2.lock())
        self.assertTrue(b1.unlock())

        self.assertTrue(b2.lock())
        self.assertFalse(b1.lock())
        self.assertTrue(b2.unlock())

        self.assertTrue(b3.lock())
        self.assertFalse(b1.lock())
        self.assertFalse(b2.lock())
        self.assertFalse(b1.unlock())
        self.assertFalse(b2.unlock())
        self.assertTrue(b3.unlock())

        self.assertTrue(b1.lock())
        self.assertTrue(b1.unlock())
Example #17
0
class DNSBuildTest(TestCase):
    fixtures = ['dns_build_test.json']

    def setUp(self):
        if not os.path.isdir(BINDBUILD['stage_dir']):
            os.makedirs(BINDBUILD['stage_dir'])

        if not os.path.isdir(BINDBUILD['prod_dir']):
            os.makedirs(BINDBUILD['prod_dir'])
        remove_dir_contents(BINDBUILD['prod_dir'])

        if not os.path.isdir(PROD_ORIGIN_DIR):
            os.makedirs(PROD_ORIGIN_DIR)
        remove_dir_contents(PROD_ORIGIN_DIR)

        mgr = GitRepoManager(debug=False, log_syslog=False, config={
            'user.name': 'test',
            'user.email': 'test',
        })
        mgr.init(PROD_ORIGIN_DIR, bare=True)
        mgr.clone(PROD_ORIGIN_DIR, BINDBUILD['prod_dir'])

        self.builder = DNSBuilder(verbose=False, debug=False, **BINDBUILD)
        self.builder.repo.commit_and_push(empty=True, message='Initial commit')

        super(DNSBuildTest, self).setUp()

    def test_force(self):
        """Test that the 'force' argument works"""

        self.builder.build(force=True)
        self.builder.push(sanity_check=False)
        rev1 = self.builder.repo.get_revision()

        sleep(1)  # Ensure different serial if rebuilt.
        self.builder.build()
        self.builder.push(sanity_check=False)
        rev2 = self.builder.repo.get_revision()

        self.assertEqual(rev1, rev2)

        sleep(1)  # Ensure different serial if rebuilt.
        self.builder.build(force=True)
        self.builder.push(sanity_check=False)
        rev3 = self.builder.repo.get_revision()

        self.assertNotEqual(rev2, rev3)

    def test_build_queue(self):
        """Test that the build queue works"""

        self.builder.build(force=True)
        self.builder.push(sanity_check=False)
        rev1 = self.builder.repo.get_revision()

        CNAME.objects.get(fqdn='foo.example.com').delete()
        s = StaticInterface.objects.get(fqdn='www.example.com')
        s.domain.soa.schedule_rebuild()

        sleep(1)  # Ensure different serial if rebuilt.
        self.builder.build()
        self.builder.push(sanity_check=False)
        rev2 = self.builder.repo.get_revision()

        self.assertNotEqual(rev1, rev2)

    def test_sanity_check1(self):
        """Test that the sanity check fails when too many lines are changed"""

        self.builder.repo.line_change_limit = 2
        self.builder.repo.line_removal_limit = 100

        self.builder.build(force=True)
        self.builder.push(sanity_check=False)

        s = StaticInterface.objects.create(
            system=System.objects.get(name='Test system'),
            label='www3',
            domain=Domain.objects.get(name='example.com'),
            ip_str='192.168.0.50',
            mac='01:23:45:01:23:45',
            ctnr=Ctnr.objects.get(name='Global')
        )
        s.views.add(
            View.objects.get(name='public'),
            View.objects.get(name='private'))

        self.builder.build()
        self.assertRaises(
            SanityCheckFailure, self.builder.push, sanity_check=True)

    def test_sanity_check2(self):
        """Test that the sanity check fails when too many lines are removed"""

        self.builder.repo.line_change_limit = 100
        self.builder.repo.line_removal_limit = 2

        self.builder.build(force=True)
        self.builder.push(sanity_check=False)

        CNAME.objects.get(fqdn='foo.example.com').delete()
        StaticInterface.objects.filter(
            fqdn__in=('www.example.com', 'www2.example.com')).delete()

        self.builder.build()
        self.assertRaises(
            SanityCheckFailure, self.builder.push, sanity_check=True)

    def test_sanity_check3(self):
        """Test that the sanity check succeeds when changes are sane"""

        self.builder.repo.line_change_limit = 100
        self.builder.repo.line_removal_limit = 100

        self.builder.build(force=True)
        self.builder.push(sanity_check=False)

        CNAME.objects.get(fqdn='foo.example.com').delete()
        StaticInterface.objects.filter(
            fqdn__in=('www.example.com', 'www2.example.com')).delete()

        self.builder.build()
        self.builder.push(sanity_check=True)
Example #18
0
File: main.py Project: jirwin/cyder
def main():
    parser = argparse.ArgumentParser(description='DNS Build scripts')
    parser.add_argument('--stage-only',
                        dest='STAGE_ONLY',
                        action='store_true',
                        default=False,
                        help="Just build staging and don't "
                        "copy to prod. named-checkzone will still be run.")
    parser.add_argument('--clobber-stage',
                        dest='CLOBBER_STAGE',
                        action='store_true',
                        default=False,
                        help="If stage "
                        "already exists delete it before running the build "
                        "script.")
    parser.add_argument('--ship-it',
                        dest='PUSH_TO_PROD',
                        action='store_true',
                        default=False,
                        help="Check files "
                        "into rcs and push upstream.")
    parser.add_argument('--preserve-stage',
                        dest='PRESERVE_STAGE',
                        action='store_true',
                        default=False,
                        help="Do not "
                        "remove staging area after build completes.")
    parser.add_argument('--no-build',
                        dest='BUILD_ZONES',
                        action='store_false',
                        default=True,
                        help="Do not "
                        "build zone files.")
    parser.add_argument('--no-syslog',
                        dest='LOG_SYSLOG',
                        action='store_false',
                        default=True,
                        help="Do not "
                        "log to syslog.")
    parser.add_argument('--debug',
                        dest='DEBUG',
                        action='store_true',
                        default=False,
                        help="Print "
                        "copious amounts of text.")
    parser.add_argument('--first-run',
                        dest='FIRST_RUN',
                        action='store_true',
                        default=False,
                        help="Ignore "
                        "all change delta thresholds.")
    nas = parser.parse_args(sys.argv[1:])
    b = DNSBuilder(**dict(nas._get_kwargs()))
    try:
        b.build_dns()
    except BuildError as why:
        b.log('LOG_ERR', why)
        #fail_mail(message.format(why))
    except Exception as err:
        # Make some noise
        #fail_mail(message.format(err))
        b.log('LOG_CRIT', err)
        raise
Example #19
0
    def test_lock_unlock(self):
        if os.path.exists(self.lock_file):
            os.remove(self.lock_file)
        b1 = DNSBuilder(STAGE_DIR=self.stage_dir, PROD_DIR=self.prod_dir, LOCK_FILE=self.lock_file)
        b2 = DNSBuilder(STAGE_DIR=self.stage_dir, PROD_DIR=self.prod_dir, LOCK_FILE=self.lock_file)
        b3 = DNSBuilder(STAGE_DIR=self.stage_dir, PROD_DIR=self.prod_dir, LOCK_FILE=self.lock_file)
        self.assertFalse(os.path.exists(self.lock_file))
        self.assertTrue(b1.lock())
        self.assertTrue(os.path.exists(self.lock_file))
        self.assertTrue(b1.unlock())

        self.assertTrue(b1.lock())
        self.assertFalse(b2.lock())
        self.assertFalse(b2.lock())
        self.assertTrue(b1.unlock())

        self.assertTrue(b2.lock())
        self.assertFalse(b1.lock())
        self.assertTrue(b2.unlock())

        self.assertTrue(b3.lock())
        self.assertFalse(b1.lock())
        self.assertFalse(b2.lock())
        self.assertFalse(b1.unlock())
        self.assertFalse(b2.unlock())
        self.assertTrue(b3.unlock())

        self.assertTrue(b1.lock())
        self.assertTrue(b1.unlock())
Example #20
0
    def test_change_a_record(self):
        root_domain = create_fake_zone('asdfz1')
        b = DNSBuilder(STAGE_DIR=self.stage_dir, PROD_DIR=self.prod_dir,
                       LOCK_FILE=self.lock_file, LOG_SYSLOG=False,
                       FIRST_RUN=True, PUSH_TO_PROD=False,
                       STOP_UPDATE_FILE=self.stop_update_file)

        b.build_dns()  # This won't check anything in since PUSH_TO_PROD==False
        self.assertEqual((26, 0), b.svn_lines_changed(b.PROD_DIR))
        b.PUSH_TO_PROD = True
        b.build_dns()  # This checked stuff in

        # no lines should have changed
        b.build_dns()
        self.assertEqual((0, 0), b.svn_lines_changed(b.PROD_DIR))

        # Now add a record.
        a, c = AddressRecord.objects.get_or_create(
            label='', domain=root_domain, ip_str="10.0.0.1", ip_type='4'
        )
        a.views.add(View.objects.get_or_create(name='private')[0])
        if not c:
            a.ttl = 8
            a.save()

        self.assertTrue(SOA.objects.get(pk=root_domain.soa.pk).dirty)
        tmp_serial = SOA.objects.get(pk=root_domain.soa.pk).serial

        b.PUSH_TO_PROD = False  # Task isn't deleted
        b.build_dns()  # Serial get's incrimented
        self.assertEqual(
            SOA.objects.get(pk=root_domain.soa.pk).serial, tmp_serial + 1
        )
        self.assertFalse(SOA.objects.get(pk=root_domain.soa.pk).dirty)
        # added new record (1) and new serials (2 for both views), old serials
        # removed.
        self.assertEqual((3, 2), b.svn_lines_changed(b.PROD_DIR))

        tmp_serial = SOA.objects.get(pk=root_domain.soa.pk).serial
        self.assertFalse(SOA.objects.get(pk=root_domain.soa.pk).dirty)

        b.PUSH_TO_PROD = True
        b.build_dns()
        self.assertFalse(SOA.objects.get(pk=root_domain.soa.pk).dirty)
        # Serial is again incremented because PUSH_TO_PROD was False during the
        # last build. When PUSH_TO_PROD is false, no scheduled tasts are
        # deleted so we should still see this soa being rebuilt.
        self.assertEqual(
            SOA.objects.get(pk=root_domain.soa.pk).serial, tmp_serial + 1
        )
        self.assertEqual((0, 0), b.svn_lines_changed(b.PROD_DIR))

        # no lines should have changed if we would have built again

        self.assertFalse(SOA.objects.get(pk=root_domain.soa.pk).dirty)
        tmp_serial = SOA.objects.get(pk=root_domain.soa.pk).serial
        b.PUSH_TO_PROD = False
        b.build_dns()
        self.assertEqual(SOA.objects.get(pk=root_domain.soa.pk).serial,
                         tmp_serial)
        self.assertFalse(SOA.objects.get(pk=root_domain.soa.pk).dirty)
        self.assertEqual((0, 0), b.svn_lines_changed(b.PROD_DIR))
Example #21
0
    def test_two_file_svn_lines_changed(self):
        b = DNSBuilder(STAGE_DIR=self.stage_dir, PROD_DIR=self.prod_dir,
                       LOCK_FILE=self.lock_file, LOG_SYSLOG=False,
                       FIRST_RUN=True, PUSH_TO_PROD=False,
                       STOP_UPDATE_FILE=self.stop_update_file)
        test1_file = os.path.join(self.prod_dir, 'test1')
        test2_file = os.path.join(self.prod_dir, 'test2')
        with open(test1_file, 'w+') as fd:
            fd.write('line 1.1\n')

        lc = b.svn_lines_changed(b.PROD_DIR)
        self.assertEqual((1, 0), lc)
        b.svn_checkin(lc)

        with open(test1_file, 'w+') as fd:
            fd.write('line 1.1\nline 1.2\n')
        with open(test2_file, 'w+') as fd:
            fd.write('line 2.1\nline 2.2\n')

        lc = b.svn_lines_changed(b.PROD_DIR)
        self.assertEqual((3, 0), lc)
        b.svn_checkin(lc)

        with open(test1_file, 'w+') as fd:
            fd.write('line 1\n')

        lc = b.svn_lines_changed(b.PROD_DIR)
        self.assertEqual((1, 2), lc)
        b.svn_checkin(lc)

        with open(test1_file, 'w+') as fd:
            fd.write('line 1.1\nline 1.2\n')
        with open(test2_file, 'w+') as fd:
            fd.write('line 2.3\nline 2.4\n')

        lc = b.svn_lines_changed(b.PROD_DIR)
        self.assertEqual((4, 3), lc)
        b.svn_checkin(lc)