Exemplo n.º 1
0
class ViewSourceViewTests(TestCase):
    def setUp(self):
        self.client = Client()
        self.redirect = RedirectFactory()
        self.microsite = CanonicalMicrositeFactory()
        self.manipulation = DestinationManipulationFactory()
        self.redirect_guid = clean_guid(self.redirect.guid)

        self.factory = RequestFactory()

    def tearDown(self):
        """
        The cache is not cleared between tests. We need to do it manually.
        """
        cache.clear()

    def test_get_with_bad_vsid(self):
        """
        If no view source id is provided or the given view source id does not
        resolve to a DestinationManipulation instance, default to 0
        """
        for vsid in ['', '1']:
            response = self.client.get(reverse('home',
                                               args=[self.redirect_guid,
                                                     vsid]))

            test_url = '%s%s/job/?vs=%s' % \
                (self.microsite.canonical_microsite_url,
                 self.redirect_guid,
                 vsid or '0')

            self.assertEqual(response['Location'], test_url)

    def test_with_action_type_2(self):
        """
        Sometimes a DestinationManipulation object exists with an action_type
        of 2 but a corresponding object with an action_type of 1 does not
        exist. If one of these is encountered, we should not run the
        manipulation twice.
        """
        self.manipulation.action_type = '2'
        self.manipulation.action = 'sourcecodetag'
        self.manipulation.value_1 = '?src=foo'
        self.manipulation.view_source = 10
        self.redirect.url = 'http://www.directemployers.org'
        self.manipulation.save()
        self.redirect.save()

        with self.assertRaises(DestinationManipulation.DoesNotExist):
            DestinationManipulation.objects.get(
                buid=self.manipulation.buid,
                view_source=self.manipulation.view_source,
                action_type=1)

        response = self.client.get(
            reverse('home',
                    args=[self.redirect_guid,
                          self.manipulation.view_source]))

        self.assertEqual(response.status_code, 301)
        self.assertEqual(response['Location'],
                         self.redirect.url + self.manipulation.value_1)

    def test_get_with_malformed_guid(self):
        """
        Navigating to a url with a malformed guid or a guid that contains
        non-hex characters should display a 404 page
        """
        for guid in [self.redirect_guid[:16],
                     'g' * 32]:
            with self.assertRaises(NoReverseMatch):
                self.client.get(reverse('home', args=[guid]))

    def test_job_does_not_exist(self):
        """
        Nonexistent jobs should display a 404 page.
        """
        response = self.client.get(reverse('home', args=['1' * 32]))
        self.assertEqual(response.status_code, 404)
        self.assertTemplateUsed(response, '404.html')
        self.assertTrue('There was an error accessing this job'
                        in response.content)
        self.assertTrue('google-analytics' in response.content)

    def test_open_graph_redirect(self):
        """
        Check social bot open graph response
        """
        response = self.client.get(
            reverse('home', args=[self.redirect_guid,
                                  self.manipulation.view_source]),
            HTTP_USER_AGENT='facebookexternalhit')
        self.assertContains(response, 'My.jobs - Programmer - DirectEmployers')
        self.assertTemplateUsed(response, 'redirect/opengraph.html')
        self.assertTrue('google-analytics' not in response.content)

    def test_twitter_card(self):
        response = self.client.get(
            reverse('home', args=[self.redirect_guid,
                                  self.manipulation.view_source]),
            HTTP_USER_AGENT='TwitterBot')
        self.assertTemplateUsed(response, 'redirect/twitter.html')
        self.assertTrue('twitter:image:src' in response.content)

    def test_sourcecodetag_redirect(self):
        """
        Check view that manipulates a url with the sourcecodetag action
        creates the correct redirect url which will have a sourcecode tag on
        the end
        examples: &Codes=DE-DEA, &src=JB-11380, &src=indeed_test
        """
        response = self.client.get(
            reverse('home', args=[self.redirect_guid,
                                  self.manipulation.view_source]))
        #content = json.loads(response.content)
        test_url = '%s?%s' % (self.redirect.url,
                              self.manipulation.value_1[1:])
        self.assertEqual(response['Location'], test_url)

    def test_microsite_redirect(self):
        """
        Ensure that requests for a given GUID + view source redirect to a
        microsite given two criteria:
        - The view source is not an excluded view source
        - The buid that owns the job has a microsite enabled.
        """
        self.manipulation.action = 'sourcecodetag'
        self.manipulation.value_1 = '?src=foo'
        self.manipulation.view_source = 0
        self.manipulation.save()

        response = self.client.get(
            reverse('home', args=[self.redirect_guid,
                                  self.manipulation.view_source]))
        test_url = '%s%s/job/?vs=%s' % (self.microsite.canonical_microsite_url,
                                        self.redirect_guid,
                                        self.manipulation.view_source)
        self.assertEqual(response['Location'], test_url)

    def test_amptoamp_redirect(self):
        """
        Check method that manipulates a url with the amptoamp action
        """
        self.manipulation.action = 'amptoamp'
        self.manipulation.value_1 = 'http://ad.doubleclick.net/clk;2526;8138?'
        self.manipulation.value_2 = '&functionName=viewFromLink&locale=en-us'
        self.manipulation.save()

        self.redirect.url = 'jobsearch.lilly.com/ddddddd/job/&8888888&vs=43'
        self.redirect.save()

        response = self.client.get(
            reverse('home', args=[self.redirect_guid,
                                  self.manipulation.view_source]))
        url = self.redirect.url.split('&')
        test_url = '%s%s%s' % \
            (self.manipulation.value_1, url[1], self.manipulation.value_2)
        self.assertEqual(response['Location'], test_url)

    def test_urlswap_redirect(self):
        """
        Check method that manipulates a url with the cframe action
        """
        self.manipulation.action = 'urlswap'
        self.manipulation.value_1 = 'https://careers.nscorp.com/?sap-client=100'
        self.manipulation.save()

        response = self.client.get(
            reverse('home', args=[self.redirect_guid,
                                  self.manipulation.view_source]))
        test_url = self.manipulation.value_1
        self.assertEqual(response['Location'], test_url)

    def test_cframe_redirect(self):
        """
        Check method that manipulates a url with the cframe action
        """
        self.manipulation.action = 'cframe'
        self.manipulation.value_1 = 'fedex.asp'
        self.manipulation.save()

        response = self.client.get(
            reverse('home', args=[self.redirect_guid,
                                  self.manipulation.view_source]))
        url = urlquote_plus(self.redirect.url, safe='')
        url = url.replace('.', '%2E')
        url = url.replace('-', '%2D')
        url = url.replace('_', '%5F')
        url = '%s?url=%s' % (self.manipulation.value_1, url)
        test_url = 'http://directemployers.us.jobs/companyframe/' + url
        self.assertEqual(response['Location'], test_url)

    def test_anchorredirectissue_redirect(self):
        """
        Check method that manipulates a url with the anchorredirectissue action
        """
        self.manipulation.action = 'anchorredirectissue'
        self.manipulation.value_1 = '&deaanchor='
        self.manipulation.save()

        self.redirect.url = 'directemployers.org/#directemployers#105/'
        self.redirect.save()

        response = self.client.get(
            reverse('home', args=[self.redirect_guid,
                                  self.manipulation.view_source]))
        url = self.redirect.url.split('#')
        test_url = 'http://testserver/' + url[0] + self.manipulation.value_1
        self.assertEqual(response['Location'], test_url)

    def test_replacethenadd_redirect(self):
        """
        Check method that manipulates a url with the replacethenadd action
        """
        self.manipulation.action = 'replacethenadd'
        self.manipulation.value_1 = 'jobdetail.ftl!!!!jobapply.ftl'
        self.manipulation.value_2 = '&src=CWS-12480'
        self.manipulation.save()

        self.redirect.url = 'directemployers.org/'
        self.redirect.save()

        response = self.client.get(
            reverse('home', args=[self.redirect_guid,
                                  self.manipulation.view_source]))
        old, new = self.manipulation.value_1.split('!!!!')
        test_url = 'http://testserver/%s%s' % \
            (self.redirect.url, self.manipulation.value_2.replace('&', '?'))
        self.assertEqual(response['Location'], test_url)

    def test_replacethenaddpre_redirect(self):
        """
        Check method that manipulates a url with the replacethenaddpre action
        """
        self.manipulation.action = 'replacethenaddpre'
        self.manipulation.value_1 = '?ss=paid!!!!?apstr=src%3DJB-10600'
        self.manipulation.value_2 = 'http://ad.doubleclick.net/clk;2613;950;s?'
        self.manipulation.save()

    def test_sourcecodeinsertion_redirect(self):
        """
        Check method that manipulates a url with the sourcecodeinsertion action
        """
        self.manipulation.action = 'sourcecodeinsertion'
        self.manipulation.value_1 = '&src=de'
        self.manipulation.save()

        self.redirect.url = 'directemployers.org/#directemployers/'
        self.redirect.save()

        response = self.client.get(
            reverse('home', args=[self.redirect_guid,
                                  self.manipulation.view_source]))
        url = self.redirect.url.split('#')
        test_url = 'http://testserver/' + ('%s#' %
                                           self.manipulation.value_1).join(url)
        self.assertEqual(response['Location'], test_url)

    def test_sourceurlwrapappend_redirect(self):
        """
        Check method that manipulates a url with the sourceurlwrapappend action
        """
        self.manipulation.action = 'sourceurlwrapappend'
        self.manipulation.value_1 = 'http://bs.serving-sys.com/server.bs?u=$$'
        self.manipulation.value_2 = '$$'
        self.manipulation.save()

        response = self.client.get(
            reverse('home', args=[self.redirect_guid,
                                  self.manipulation.view_source]))
        url = urlquote_plus(self.redirect.url, safe='')
        url = url.replace('.', '%2E')
        url = url.replace('-', '%2D')
        url = url.replace('_', '%5F')
        test_url = self.manipulation.value_1 + url + self.manipulation.value_2
        self.assertEqual(response['Location'], test_url)

    def test_sourceurlwrapunencodedappend_redirect(self):
        """
        Check method that manipulates a url with the
        sourceurlwrapunencodedappend action
        """
        self.manipulation.action = 'sourceurlwrapunencodedappend'
        self.manipulation.value_1 = 'http://ad.doubleclick.net/clk;2593;886;r?'
        self.manipulation.value_2 = '&SID=97'
        self.manipulation.save()

        response = self.client.get(
            reverse('home', args=[self.redirect_guid,
                                  self.manipulation.view_source]))
        #content = json.loads(response.content)
        url = self.manipulation.value_1 + self.redirect.url
        test_url = url + self.manipulation.value_2
        self.assertEqual(response['Location'], test_url)

    def test_sourceurlwrapunencoded_redirect(self):
        """
        Check method that manipulates a url with the sourceurlwrapunencoded
        action
        """
        self.manipulation.action = 'sourceurlwrapunencoded'
        self.manipulation.value_1 = 'http://ad.doubleclick.net/clk;346;154;h?'
        self.manipulation.save()

        response = self.client.get(
            reverse('home', args=[self.redirect_guid,
                                  self.manipulation.view_source]))
        test_url = self.manipulation.value_1 + self.redirect.url
        self.assertEqual(response['Location'], test_url)

    def test_sourceurlwrap_redirect(self):
        """
        Check method that manipulates a url with the sourceurlwrap action
        """
        self.manipulation.action = 'sourceurlwrap'
        self.manipulation.value_1 = 'http://bs.serving-sys.com/?cn=t&rtu=$$'
        self.manipulation.save()

        response = self.client.get(
            reverse('home', args=[self.redirect_guid,
                                  self.manipulation.view_source]))
        url = urlquote_plus(self.redirect.url, safe='')
        url = url.replace('.', '%2E')
        url = url.replace('-', '%2D')
        url = url.replace('_', '%5F')
        test_url = self.manipulation.value_1 + url
        self.assertEqual(response['Location'], test_url)

    def test_switchlastinstance_redirect(self):
        """
        Check method that manipulates a url with the switchlastinstance action
        """
        self.manipulation.action = 'switchlastinstance'
        self.manipulation.value_1 = '/job'
        self.manipulation.value_2 = '/login'
        self.manipulation.save()

        self.redirect.url = 'directemployers.org/job'
        self.redirect.save()

        response = self.client.get(
            reverse('home', args=[self.redirect_guid,
                                  self.manipulation.view_source]))
        old = self.manipulation.value_1
        new = self.manipulation.value_2
        test_url = 'http://testserver/' + new.join(
            self.redirect.url.rsplit(old, 1))
        self.assertEqual(response['Location'], test_url)

    def test_switchlastthenadd_redirect(self):
        """
        Check method that manipulates a url with the switchlastthenadd action
        """
        self.manipulation.action = 'switchlastthenadd'
        self.manipulation.value_1 = '/job!!!!/login'
        self.manipulation.value_2 = '?iis=CareerSiteSEO'
        self.manipulation.save()

        self.redirect.url = 'directemployers.org/job'
        self.redirect.save()

        response = self.client.get(
            reverse('home', args=[self.redirect_guid,
                                  self.manipulation.view_source]))
        old, new = self.manipulation.value_1.split('!!!!')
        new_url = new.join(self.redirect.url.rsplit(old, 1))
        test_url = 'http://testserver/' + new_url + self.manipulation.value_2
        self.assertEqual(response['Location'], test_url)

    def test_state_job(self):
        self.redirect.buid = 1228
        self.redirect.url = 'http://us.jobs/viewjobs.asp?jobid=1234'
        self.redirect.job_location = 'NY-Rochester'
        self.manipulation.delete()
        self.redirect.save()
        response = self.client.get(
            reverse('home', args=[self.redirect_guid,
                                  self.manipulation.view_source]))
        self.assertTrue(self.redirect.url.replace('us.jobs', 'newyork.us.jobs')
                        in response['Location'])

    def test_expired_job(self):
        self.redirect.expired_date = datetime.datetime.now(tz=timezone.utc)
        self.redirect.save()

        response = self.client.get(
            reverse('home', args=[self.redirect_guid,
                                  self.manipulation.view_source]))
        self.assertEqual(response.status_code, 410)
        self.assertTemplateUsed(response, 'redirect/expired.html')

        content = re.sub('\s+', ' ', response.content)
        self.assertTrue('View all jobs for<br /> <b>%s</b>' %
                        self.redirect.company_name in
                        content)

        count = content.count('class="drill-search"')
        self.assertEqual(count, 3,
                         'Expected three search links, found %s' % count)
        self.assertTrue(self.redirect.url in response.content)
        self.assertTrue('google-analytics' in response.content)

    def test_expired_job_with_unicode(self):
        self.redirect.expired_date = datetime.datetime.now(tz=timezone.utc)
        self.redirect.job_title = u'это юникода'
        self.redirect.save()

        response = self.client.get(reverse('home',
                                           args=[self.redirect_guid]))
        self.assertTrue(response.status_code, 404)

    def test_cookie_domains(self):
        # The value for host is unimportant - if this code does not end up
        # being served on r.my.jobs, it's okay. We're just testing that we
        # properly retrieve the root domain from what is provided.
        for host in ['jcnlx.com', 'my.jobs', 'r.my.jobs']:
            request = self.factory.get(
                reverse('home', args=[self.redirect_guid,
                                      self.manipulation.view_source]),
                HTTP_HOST=host)
            response = home(request, self.redirect_guid,
                            self.manipulation.view_source)

            cookie = response.cookies['aguid']
            if 'my.jobs' in host:
                expected_domain = '.my.jobs'
            else:
                expected_domain = '.jcnlx.com'
            self.assertIn(('domain', expected_domain), cookie.items())
            uuid.UUID(unquote(cookie.value))

    def test_apply_click(self):
        self.apply_manipulation = DestinationManipulationFactory(
            view_source=1234)

        response = self.client.get(reverse('home',
                                           args=[self.redirect_guid]) +
                                   '?vs=%s' %
                                   self.apply_manipulation.view_source)
        self.assertEqual(response.status_code, 301)

        test_url = '%s?%s' % (self.redirect.url,
                              self.apply_manipulation.value_1[1:])

        self.assertEqual(response['Location'], test_url)

    def test_bad_vs_query(self):
        self.apply_manipulation = DestinationManipulationFactory(
            view_source=1234)

        response = self.client.get(reverse('home',
                                           args=[self.redirect_guid]) +
                                   '?vs=%sbad_vs' %
                                   self.apply_manipulation.view_source)

        self.assertTrue(response['Location'].endswith(self.redirect.url))

    def test_source_code_collision(self):
        """
        Test that we never duplicate source codes in the event of a collision

        Tests five circumstances:
        - The source code is the last entry in the query
        - The source code is somewhere in the middle
        - The source code is the first query
        - The source code is the only query
        - The new source code has a blank value
        """
        url = 'http://directemployers.jobs?%ssrc=de%s'
        for part in [('foo=bar&', ''),  # last
                     ('foo=bar&', '&code=de'),  # middle
                     ('', '&foo=bar'),  # first
                     ('', '')]:  # only
            self.redirect.url = url % part
            self.redirect.save()
            self.manipulation.value_1 = '&src=JB-DE'
            self.manipulation.save()

            response = self.client.get(
                reverse('home',
                        args=[self.redirect_guid,
                              self.manipulation.view_source]))

            self.assertTrue('src=de' not in response['Location'])
            self.assertTrue('src=JB-DE' in response['Location'])

        # New source code is blank
        self.manipulation.value_1 = '?src='
        self.manipulation.save()
        response = self.client.get(
            reverse('home',
                    args=[self.redirect_guid,
                          self.manipulation.view_source]))
        self.assertEqual(response['Location'],
                         self.redirect.url.replace('de', ''))

    def test_source_codes_ignore_case(self):
        """
        Source codes should be matched case-insensitively between what is
        already applied to a url and what we are adding. If a matching source
        code is already in place, its value should be replaced with the new
        value. If no matching source code is found, we should append the
        new one and keep its case.
        """
        old_url = self.redirect.url
        parameters = ['src', 'SRC']
        for url_param in parameters:
            self.redirect.url = '%s?%s=code' % (old_url, url_param)
            self.redirect.save()

            for manipulation_param in parameters:
                self.manipulation.value_1 = '?%s=foo' % manipulation_param
                self.manipulation.save()

                response = self.client.get(
                    reverse('home',
                            args=[self.redirect_guid,
                                  self.manipulation.view_source]))
                self.assertEqual(response['Location'],
                                 self.redirect.url.replace('code', 'foo'))

    def test_source_code_with_encoded_parameters(self):
        """
        Sometimes the value that we're adding has %-encoded values already;
        Ensure that we don't accidentally unencode or double-encode those
        values (ie %20->%2520)
        """
        self.manipulation.value_1 = '&src=with%20space'
        self.manipulation.save()

        response = self.client.get(
            reverse('home',
                    args=[self.redirect_guid,
                          self.manipulation.view_source]))

        # We ensure that there is never a & without a preceding ? - that is
        # unlikely, however
        self.assertTrue('?' + self.manipulation.value_1[1:] in
                        response['Location'])

    def test_invalid_sourcecodetag_redirect(self):
        """
        In the event that the desired source code is not present in the
        database somehow, performing a sourcecodetag redirect should result
        in that source code not being added to the final url
        """
        self.manipulation.value_1 = ''
        self.manipulation.save()

        response = self.client.get(
            reverse('home',
                    args=[self.redirect_guid,
                          self.manipulation.view_source]))

        self.assertTrue(response['Location'].endswith(self.redirect.url))

    def test_myjobs_redirects(self):
        paths = ['/terms', '/search?location=Indianapolis']
        for path in paths:
            response = self.client.get(path, follow=True)
            self.assertEqual(response.status_code, 301)
            self.assertTrue(response['Location'].startswith(
                'http://www.my.jobs'))

    def test_debug_parameter(self):
        response = self.client.get(reverse('home',
                                           args=[self.redirect_guid,
                                                 self.manipulation.view_source,
                                                 '+']))
        self.assertTrue(self.redirect.guid in response.content)
        self.assertTrue(self.redirect.url in response.content)
        self.assertEqual(response.status_code, 200)
        self.assertTrue('google-analytics' in response.content)

    def test_redirect_on_new_job(self):
        """
        Ensure that are not done if a job was added
        within the last 30 minutes
        """
        # Make the redirect and manipulation objects look like real data
        self.redirect.new_date = datetime.datetime.now(tz=timezone.utc)
        self.redirect.url = 'http://www.directemployers.org'
        self.redirect.save()
        self.manipulation.action = 'sourcecodetag'
        self.manipulation.value_1 = '?src=foo'
        self.manipulation.view_source = 0
        self.manipulation.save()

        response = self.client.get(reverse('home',
                                           args=[self.redirect_guid]))

        # The job would normally redirect to a microsite, but it should not
        # in this instance
        self.assertFalse(response['Location'].startswith(
            self.microsite.canonical_microsite_url))
        # ... while the result of doing a sourcecodeswitch does.
        self.assertTrue(self.manipulation.value_1 in response['Location'])

        # If a job is 30 minutes old or older, the microsite result is used
        # as expected.
        self.redirect.new_date -= datetime.timedelta(minutes=30)
        self.redirect.save()
        response = self.client.get(reverse('home',
                                           args=[self.redirect_guid]))
        test_url = '%s%s/job/?vs=%s' % (self.microsite.canonical_microsite_url,
                                        self.redirect_guid,
                                        self.manipulation.view_source)
        self.assertEqual(response['Location'], test_url)

    def test_percent_encoded_url_params(self):
        """
        Ensure that query parameters retain their encoding when adding new
        parameters.
        """
        self.redirect.url = 'example.com?%c3%81=%20%3d,%2b'
        self.redirect.save()
        response = self.client.get(
            reverse('home',
                    args=[self.redirect_guid,
                          self.manipulation.view_source]))
        self.assertTrue('%c3%81=%20%3d,%2b' in response['Location'].lower())

    def test_cache_gets_set_on_view(self):
        """
        Viewing any page when the cache is empty should populate a list of
        excluded view sources
        """
        cache_key = settings.EXCLUDED_VIEW_SOURCE_CACHE_KEY
        cache.delete(cache_key)

        self.assertFalse(cache.get(cache_key))

        self.client.get(reverse('home',
                                args=[self.redirect_guid]))

        self.assertTrue(cache.get(cache_key))

    def test_cache_gets_cleared_on_save(self):
        """
        Saving an ExpiredViewSource object should remove the list of
        excluded view sources, which will be replaced on the next request
        """
        cache_key = settings.EXCLUDED_VIEW_SOURCE_CACHE_KEY
        self.client.get(reverse('home',
                                args=[self.redirect_guid]))

        new_evs = ExcludedViewSource.objects.all().order_by('-view_source')[0]
        new_evs = new_evs.view_source + 1

        self.assertFalse(new_evs in cache.get(cache_key))

        ExcludedViewSource(view_source=new_evs).save()

        self.assertFalse(cache.get(cache_key))

        self.client.get(reverse('home',
                                args=[self.redirect_guid]))

        self.assertTrue(new_evs in cache.get(cache_key))

    def test_custom_microsite_exclusion(self):
        custom_exclusion = CustomExcludedViewSourceFactory()

        response = self.client.get(
            reverse('home',
                    args=[self.redirect_guid,
                          custom_exclusion.view_source]))
        self.assertTrue((custom_exclusion.buid,
                         custom_exclusion.view_source) in
                        settings.CUSTOM_EXCLUSIONS)
        self.assertFalse(response['Location'].startswith(
            self.microsite.canonical_microsite_url))

    def test_custom_parameters(self):
        CustomExcludedViewSourceFactory(
            view_source=self.manipulation.view_source)
        response = self.client.get(
            reverse('home',
                    args=[self.redirect_guid,
                          self.manipulation.view_source]) + '?z=1&foo=bar')
        for part in [self.redirect.url,
                     'foo=bar',
                     self.manipulation.value_1[1:]]:
            self.assertTrue(part in response['Location'])

    def test_custom_parameters_on_microsite(self):
        self.manipulation.view_source = 0
        self.manipulation.save()
        response = self.client.get(
            reverse('home',
                    args=[self.redirect_guid]) + '?z=1&foo=bar')
        test_url = '%s%s/job/?vs=%s&z=1&foo=bar' % \
                   (self.microsite.canonical_microsite_url,
                    self.redirect_guid,
                    self.manipulation.view_source)
        self.assertEqual(response['Location'], test_url)

        response = self.client.get(
            reverse('home',
                    args=[self.redirect_guid]) + '?vs=0&z=1&foo=bar')
        test_url = '%s?%s&foo=bar' % (self.redirect.url,
                                      self.manipulation.value_1[1:])
        self.assertEqual(response['Location'], test_url)

    def test_custom_parameters_on_doubleclick(self):
        self.manipulation.action = 'doubleclickwrap'
        self.manipulation.value_1 = 'http://ad.doubleclick.net/clk;2613;950;s?'
        self.manipulation.save()

        response = self.client.get(
            reverse('home',
                    args=[self.redirect_guid,
                          self.manipulation.view_source]) + '?z=1&foo=bar')
        test_url = '%s%s?foo=bar' % (self.manipulation.value_1,
                                     self.redirect.url)
        self.assertEqual(response['Location'], test_url)

    def test_custom_parameters_on_feed_redirect(self):
        site = Site.objects.create(domain='google.com',
                                   name='Google')
        response = self.client.get(
            reverse('home',
                    args=[self.redirect_guid,
                          '20']) + '?z=1&foo=bar&my.jobs.site.id=%d' % site.pk)
        parts = urlparse.urlparse(response['Location'])
        self.assertEqual(parts.netloc, site.domain)

        query = urlparse.parse_qs(parts.query)
        for param in {'z': ['1'], 'foo': ['bar'],
                      'vs': ['20']}.items():
            self.assertEqual(query[param[0]], param[1])

        # When redirecting from a feed and using custom parameters, we create
        # the potential for a redirect loop. Ensure that isn't happening.
        self.assertRaises(KeyError, lambda: query['my.jobs.site.id'])

    def test_source_codes_with_hit_key(self):
        self.manipulation.action = 'replacethenadd'
        self.manipulation.value_1 = '/job!!!!/apply'
        self.manipulation.value_2 = '&src=foo'
        self.manipulation.save()

        self.redirect.url = 'http://www.directemployers.org/job#hit-key'
        self.redirect.save()

        expected = '/apply?src=bar#hit-key'
        response = self.client.get(
            reverse('home',
                    args=[self.redirect_guid,
                          self.manipulation.view_source]) + '?z=1&src=bar')
        self.assertTrue(response['Location'].endswith(expected))

    def test_bad_query_value(self):
        """
        A few replacethenadd instances were found that had blank values
        for the "add" portion. They have been fixed, but we should ensure that
        this doesn't 500 in the event that more are added.
        """
        self.manipulation.action = 'replacethenadd'
        self.manipulation.value_1 = '/jobdetail.ftl!!!!/jobapply.ftl'
        self.manipulation.value_2 = ''
        self.manipulation.save()

        self.redirect.url = 'http://directemployers.org/jobdetail.ftl'
        self.redirect.save()

        response = self.client.get(
            reverse('home',
                    args=[self.redirect_guid,
                          self.manipulation.view_source]))
        self.assertTrue(response['Location'].endswith('/jobapply.ftl'))
        self.assertFalse('/jobdetail.ftl' in response['Location'])

    def test_syndication_redirect_site_exists(self):
        """
        Ensures that we appropriately redirect to the proper microsite if we are
        provided one that differs from what is defined for a given BUID.
        """
        site = Site.objects.create(domain='google.com',
                                   name='Google')
        response = self.client.get(
            reverse('home',
                    args=[self.redirect_guid,
                          self.manipulation.view_source]) +
            '?my.jobs.site.id=%s' % site.pk)

        expected = 'http://%s/%s/job/?vs=%s' % (site.domain, self.redirect_guid,
                                                self.manipulation.view_source)
        self.assertEqual(response.status_code, 301)
        self.assertEqual(response['Location'], expected)

    def test_syndication_redirect_no_site(self):
        """
        If my.jobs.site.id is provided but does not reference a site, do
        manipulations as if it was not provided.
        """
        site = Site.objects.create(domain='google.com',
                                   name='Google')
        response = self.client.get(
            reverse('home',
                    args=[self.redirect_guid,
                          self.manipulation.view_source]) +
            '?my.jobs.site.id=%s' % (site.pk + 1))

        self.assertEqual(response.status_code, 301)
        self.assertEqual(response['Location'], sourcecodetag(self.redirect,
                                                             self.manipulation))

    def test_msccn_redirect(self):
        response = self.client.get(
            reverse('home',
                    args=[self.redirect_guid,
                          '1604']))
        expected = 'http://us.jobs/msccn-referral.asp?gi=%s%s&cp=%s' % (
            self.redirect_guid, '1604', self.redirect.company_name)
        self.assertEqual(response['Location'], expected)

    def test_default_google_analytics(self):
        vs = ViewSourceFactory(include_ga_params=True)
        group = ViewSourceGroupFactory(view_sources=[vs])

        response = self.client.get(
            reverse('home',
                    args=[self.redirect_guid,
                          vs.view_source_id]))
        expected = 'http://www.my.jobs/{guid}/job/?vs={vs}' \
                   '&utm_source={source}-DE&utm_medium={group}' \
                   '&utm_campaign={source}'.format(
                       guid=self.redirect_guid, vs=vs.view_source_id,
                       source=vs.name, group=group.name).replace(' ', '%20')

        self.assertEqual(expected, response['Location'])

    def test_syndication_redirect_with_analytics(self):
        """
        Analytics parameters should be added to syndication redirects.
        """
        vs = ViewSourceFactory(include_ga_params=True)
        group = ViewSourceGroupFactory(view_sources=[vs])
        site = Site.objects.create(domain='google.com', name='google')
        response = self.client.get(
            reverse('home',
                    args=[self.redirect_guid,
                          vs.view_source_id]) +
            '?my.jobs.site.id=%s' % site.pk)
        location = unquote(response['Location'])
        self.assertTrue(location.startswith('http://%s' % site.domain))
        for query in ['&utm_source=%s-DE' % vs.name,
                      '&utm_medium=%s' % group.name,
                      '&utm_campaign=%s' % vs.name]:
            self.assertTrue(query in location)

    def test_syndication_redirect_with_analytics_and_override(self):
        """
        Syndication redirects should include any source code overrides that
        have been added.
        """
        vs = ViewSourceFactory(include_ga_params=True,
                               view_source_id=self.manipulation.view_source)
        group = ViewSourceGroupFactory(view_sources=[vs])
        site = Site.objects.create(domain='google.com', name='google')
        response = self.client.get(
            reverse('home',
                    args=[self.redirect_guid,
                          vs.view_source_id]) +
            '?my.jobs.site.id=%s&z=1&utm_source=test' % site.pk)
        location = unquote(response['Location'])
        self.assertTrue(location.startswith('http://%s' % site.domain))
        for query in ['&utm_source=test',
                      '&utm_medium=%s' % group.name,
                      '&utm_campaign=%s' % vs.name,
                      '&z=1']:
            self.assertTrue(query in location)