Beispiel #1
0
    def testZeroSum(self):
        """Tests that we fail if all allocations are zero."""

        split = {"v1": 0.0, "v2": 0.0}

        with self.assertRaises(service_util.ServicesSplitTrafficError):
            service_util.ParseTrafficAllocations(split, DECIMAL_PRECISION)
Beispiel #2
0
    def testSingleRoundedDownToZero(self):
        """Tests that we fail if one allocation is rounded down to zero."""

        split = {"v1": 1.0, "v2": 0.0001}

        with self.assertRaises(service_util.ServicesSplitTrafficError):
            service_util.ParseTrafficAllocations(split, DECIMAL_PRECISION)
Beispiel #3
0
    def testSmallNumbersMatter(self):
        """Tests that if we have two tiny numbers with a good split, it's ok."""

        split = {"v1": 0.00008, "v2": 0.00008}
        result = service_util.ParseTrafficAllocations(split, DECIMAL_PRECISION)

        expected_result = {"v1": 0.500, "v2": 0.500}
        self.assertEqual(result, expected_result)
Beispiel #4
0
    def testLessThanOneHundredIsRoundedUp(self):
        """Tests that allocations which sum less than 100 are rounded up to 100."""
        split = {"v1": 33, "v2": 33, "v3": 33}
        result = service_util.ParseTrafficAllocations(split, DECIMAL_PRECISION)

        # v1 is expected to round up, since it is the first version in a sort and
        # all allocations are equally max.
        expected_result = {"v1": 0.334, "v2": 0.333, "v3": 0.333}
        self.assertEqual(result, expected_result)
Beispiel #5
0
    def testSplitRespectsDecimalPrecision(self):
        """Tests that unparsed traffic splits properly respect precision."""

        # These allocations sum to 0.9999999999999999
        unparsed_allocations = {"v1": 50, "v2": 41, "v3": 9}
        result = service_util.ParseTrafficAllocations(unparsed_allocations,
                                                      DECIMAL_PRECISION)

        expected_result = {"v1": 0.5, "v2": 0.41, "v3": 0.09}
        self.assertEqual(result, expected_result)
Beispiel #6
0
    def testMaximumElementIsRounded(self):
        """Tests that the maximum value is picked as the element that is modified.

    This ensures that we don't mistakenly round the first value down to zero.
    """

        split = {"v1": 0.1, "v2": 49, "v3": 51}
        result = service_util.ParseTrafficAllocations(split, DECIMAL_PRECISION)

        expected_result = {"v1": 0.001, "v2": 0.49, "v3": 0.509}
        self.assertEqual(result, expected_result)
Beispiel #7
0
  def Run(self, args):
    if args.migrate and len(args.splits) > 1:
      raise TrafficSplitError('The migrate flag can only be used with splits '
                              'to a single version.')

    api_client = appengine_api_client.GetApiClientForTrack(self.ReleaseTrack())

    all_services = api_client.ListServices()
    services = service_util.GetMatchingServices(all_services, args.services)

    allocations = service_util.ParseTrafficAllocations(
        args.splits, args.split_by)

    display_allocations = []
    for service in services:
      for version, split in six.iteritems(allocations):
        display_allocations.append('{0}/{1}/{2}: {3}'.format(
            api_client.project,
            service.id,
            version,
            split))

    fmt = 'list[title="Setting the following traffic allocation:"]'
    resource_printer.Print(display_allocations, fmt, out=log.status)
    log.status.Print(
        'NOTE: Splitting traffic by {0}.'.format(args.split_by))
    log.status.Print('Any other versions of the specified service will '
                     'receive zero traffic.')
    console_io.PromptContinue(cancel_on_no=True)

    errors = {}
    for service in services:
      try:
        operations_util.CallAndCollectOpErrors(
            api_client.SetTrafficSplit, service.id, allocations,
            args.split_by.upper(), args.migrate)
      except operations_util.MiscOperationError as err:
        errors[service.id] = str(err)
    if errors:
      printable_errors = {}
      for service, error_msg in errors.items():
        printable_errors[service] = error_msg
      raise TrafficSplitError(
          'Issue setting traffic on service(s): {0}\n\n'.format(
              ', '.join(list(printable_errors.keys()))) +
          '\n\n'.join(list(printable_errors.values())))
    def Run(self, args):
        if args.migrate and len(args.splits) > 1:
            raise TrafficSplitError(
                'The migrate flag can only be used with splits '
                'to a single version.')

        api_client = appengine_api_client.GetApiClient(self.Http(timeout=None))

        all_services = api_client.ListServices()
        services = service_util.GetMatchingServices(all_services,
                                                    args.services,
                                                    api_client.project)

        allocations = service_util.ParseTrafficAllocations(
            args.splits, args.split_by)

        display_allocations = []
        for service in services:
            for version, split in allocations.iteritems():
                display_allocations.append('{0}/{1}/{2}: {3}'.format(
                    api_client.project, service.id, version, split))

        printer = console_io.ListPrinter(
            'Setting the following traffic allocations:')
        printer.Print(display_allocations, output_stream=log.status)
        log.status.Print('Any other versions on the specified services will '
                         'receive zero traffic.')
        console_io.PromptContinue(cancel_on_no=True)

        errors = {}
        for service in services:
            try:
                api_client.SetTrafficSplit(service.id, allocations,
                                           args.split_by.upper(), args.migrate)
            except (calliope_exceptions.HttpException,
                    operations.OperationError,
                    operations.OperationTimeoutError) as err:
                errors[service.id] = str(err)
        if errors:
            printable_errors = {}
            for service, error_msg in errors.items():
                printable_errors[service] = error_msg
            raise TrafficSplitError(
                'Issue setting traffic on service(s): {0}\n\n'.format(
                    ', '.join(printable_errors.keys())) +
                '\n\n'.join(printable_errors.values()))