def test_push_list_filter_by_date(client, test_repository, sample_push): """ test retrieving a push list, filtered by a date range """ for (i, datestr) in zip( [3, 4, 5, 6, 7], ["2013-08-09", "2013-08-10", "2013-08-11", "2013-08-12", "2013-08-13" ]): sample_push[i]['push_timestamp'] = utils.to_timestamp( utils.to_datetime(datestr)) store_push_data(test_repository, sample_push) resp = client.get( reverse("push-list", kwargs={"project": test_repository.name}), { "startdate": "2013-08-10", "enddate": "2013-08-13" }, ) assert resp.status_code == 200 data = resp.json() results = data['results'] meta = data['meta'] assert len(results) == 4 assert set([rs["revision"] for rs in results]) == { u'ce17cad5d554cfffddee13d1d8421ae9ec5aad82', u'7f417c3505e3d2599ac9540f02e3dbee307a3963', u'a69390334818373e2d7e6e9c8d626a328ed37d47', u'f361dcb60bbedaa01257fbca211452972f7a74b2', } assert meta == { u'count': 4, u'enddate': u'2013-08-13', u'filter_params': { u'push_timestamp__gte': 1376092800.0, u'push_timestamp__lt': 1376438400.0, }, u'repository': test_repository.name, u'startdate': u'2013-08-10', }
def test_push_list_filter_by_date(client, test_repository, sample_push): """ test retrieving a push list, filtered by a date range """ for (i, datestr) in zip( [3, 4, 5, 6, 7], ["2013-08-09", "2013-08-10", "2013-08-11", "2013-08-12", "2013-08-13" ]): sample_push[i]['push_timestamp'] = utils.to_timestamp( utils.to_datetime(datestr)) store_push_data(test_repository, sample_push) resp = client.get( reverse("push-list", kwargs={"project": test_repository.name}), { "startdate": "2013-08-10", "enddate": "2013-08-13" }) assert resp.status_code == 200 # The .json() method of the Django test client doesn't handle unicode properly on # Python 2, so we have to deserialize ourselves. TODO: Clean up once on Python 3. data = json.loads(resp.content) results = data['results'] meta = data['meta'] assert len(results) == 4 assert set([rs["revision"] for rs in results]) == { u'ce17cad5d554cfffddee13d1d8421ae9ec5aad82', u'7f417c3505e3d2599ac9540f02e3dbee307a3963', u'a69390334818373e2d7e6e9c8d626a328ed37d47', u'f361dcb60bbedaa01257fbca211452972f7a74b2' } assert (meta == { u'count': 4, u'enddate': u'2013-08-13', u'filter_params': { u'push_timestamp__gte': 1376092800.0, u'push_timestamp__lt': 1376438400.0 }, u'repository': test_repository.name, u'startdate': u'2013-08-10' })
def test_push_list_filter_by_date(client, test_repository, sample_push): """ test retrieving a push list, filtered by a date range """ for (i, datestr) in zip([3, 4, 5, 6, 7], ["2013-08-09", "2013-08-10", "2013-08-11", "2013-08-12", "2013-08-13"]): sample_push[i]['push_timestamp'] = utils.to_timestamp( utils.to_datetime(datestr)) store_push_data(test_repository, sample_push) resp = client.get( reverse("push-list", kwargs={"project": test_repository.name}), {"startdate": "2013-08-10", "enddate": "2013-08-13"} ) assert resp.status_code == 200 # The .json() method of the Django test client doesn't handle unicode properly on # Python 2, so we have to deserialize ourselves. TODO: Clean up once on Python 3. data = json.loads(resp.content) results = data['results'] meta = data['meta'] assert len(results) == 4 assert set([rs["revision"] for rs in results]) == { u'ce17cad5d554cfffddee13d1d8421ae9ec5aad82', u'7f417c3505e3d2599ac9540f02e3dbee307a3963', u'a69390334818373e2d7e6e9c8d626a328ed37d47', u'f361dcb60bbedaa01257fbca211452972f7a74b2' } assert(meta == { u'count': 4, u'enddate': u'2013-08-13', u'filter_params': { u'push_timestamp__gte': 1376092800.0, u'push_timestamp__lt': 1376438400.0 }, u'repository': test_repository.name, u'startdate': u'2013-08-10'} )
def test_resultset_list_filter_by_date(webapp, test_repository, sample_resultset, jm, test_project): """ test retrieving a resultset list, filtered by a date range """ for (i, datestr) in zip( [3, 4, 5, 6, 7], ["2013-08-09", "2013-08-10", "2013-08-11", "2013-08-12", "2013-08-13" ]): sample_resultset[i]['push_timestamp'] = utils.to_timestamp( utils.to_datetime(datestr)) jm.store_result_set_data(sample_resultset) resp = webapp.get( reverse("resultset-list", kwargs={"project": jm.project}), { "startdate": "2013-08-10", "enddate": "2013-08-13" }) assert resp.status_int == 200 results = resp.json['results'] meta = resp.json['meta'] assert len(results) == 4 assert set([rs["revision"] for rs in results]) == { u'ce17cad5d554cfffddee13d1d8421ae9ec5aad82', u'7f417c3505e3d2599ac9540f02e3dbee307a3963', u'a69390334818373e2d7e6e9c8d626a328ed37d47', u'f361dcb60bbedaa01257fbca211452972f7a74b2' } assert (meta == { u'count': 4, u'enddate': u'2013-08-13', u'filter_params': { u'push_timestamp__gte': 1376092800.0, u'push_timestamp__lt': 1376438400.0 }, u'repository': test_project, u'startdate': u'2013-08-10' })
def test_push_list_filter_by_date(webapp, test_repository, sample_push): """ test retrieving a push list, filtered by a date range """ for (i, datestr) in zip([3, 4, 5, 6, 7], ["2013-08-09", "2013-08-10", "2013-08-11", "2013-08-12", "2013-08-13"]): sample_push[i]['push_timestamp'] = utils.to_timestamp( utils.to_datetime(datestr)) store_push_data(test_repository, sample_push) resp = webapp.get( reverse("push-list", kwargs={"project": test_repository.name}), {"startdate": "2013-08-10", "enddate": "2013-08-13"} ) assert resp.status_int == 200 results = resp.json['results'] meta = resp.json['meta'] assert len(results) == 4 assert set([rs["revision"] for rs in results]) == { u'ce17cad5d554cfffddee13d1d8421ae9ec5aad82', u'7f417c3505e3d2599ac9540f02e3dbee307a3963', u'a69390334818373e2d7e6e9c8d626a328ed37d47', u'f361dcb60bbedaa01257fbca211452972f7a74b2' } assert(meta == { u'count': 4, u'enddate': u'2013-08-13', u'filter_params': { u'push_timestamp__gte': 1376092800.0, u'push_timestamp__lt': 1376438400.0 }, u'repository': test_repository.name, u'startdate': u'2013-08-10'} )
def list(self, request, project): """ GET method for list of ``push`` records with revisions """ # What is the upper limit on the number of pushes returned by the api MAX_PUSH_COUNT = 1000 # make a mutable copy of these params filter_params = request.query_params.copy() # This will contain some meta data about the request and results meta = {} # support ranges for date as well as revisions(changes) like old tbpl for param in ["fromchange", "tochange", "startdate", "enddate", "revision"]: v = filter_params.get(param, None) if v: del filter_params[param] meta[param] = v try: repository = Repository.objects.get(name=project) except Repository.DoesNotExist: return Response({ "detail": "No project with name {}".format(project) }, status=HTTP_404_NOT_FOUND) pushes = Push.objects.filter(repository=repository).order_by('-time') for (param, value) in iteritems(meta): if param == 'fromchange': frompush_time = Push.objects.values_list('time', flat=True).get( repository=repository, revision__startswith=value) pushes = pushes.filter(time__gte=frompush_time) filter_params.update({ "push_timestamp__gte": to_timestamp(frompush_time) }) elif param == 'tochange': topush_time = Push.objects.values_list('time', flat=True).get( repository=repository, revision__startswith=value) pushes = pushes.filter(time__lte=topush_time) filter_params.update({ "push_timestamp__lte": to_timestamp(topush_time) }) elif param == 'startdate': pushes = pushes.filter(time__gte=to_datetime(value)) filter_params.update({ "push_timestamp__gte": to_timestamp(to_datetime(value)) }) elif param == 'enddate': real_end_date = to_datetime(value) + datetime.timedelta(days=1) pushes = pushes.filter(time__lte=real_end_date) filter_params.update({ "push_timestamp__lt": to_timestamp(real_end_date) }) elif param == 'revision': # revision can be either the revision of the push itself, or # any of the commits it refers to pushes = pushes.filter(commits__revision__startswith=value) rev_key = "revisions_long_revision" \ if len(meta['revision']) == 40 else "revisions_short_revision" filter_params.update({rev_key: meta['revision']}) for param in ['push_timestamp__lt', 'push_timestamp__lte', 'push_timestamp__gt', 'push_timestamp__gte']: if filter_params.get(param): # translate push timestamp directly into a filter try: value = datetime.datetime.fromtimestamp( float(filter_params.get(param))) except ValueError: return Response({ "detail": "Invalid timestamp specified for {}".format( param) }, status=HTTP_400_BAD_REQUEST) pushes = pushes.filter(**{ param.replace('push_timestamp', 'time'): value }) for param in ['id__lt', 'id__lte', 'id__gt', 'id__gte', 'id']: try: value = int(filter_params.get(param, 0)) except ValueError: return Response({ "detail": "Invalid timestamp specified for {}".format( param) }, status=HTTP_400_BAD_REQUEST) if value: pushes = pushes.filter(**{param: value}) id_in = filter_params.get("id__in") if id_in: try: id_in_list = [int(id) for id in id_in.split(',')] except ValueError: return Response({"detail": "Invalid id__in specification"}, status=HTTP_400_BAD_REQUEST) pushes = pushes.filter(id__in=id_in_list) author = filter_params.get("author") if author: pushes = pushes.filter(author=author) try: count = int(filter_params.get("count", 10)) except ValueError: return Response({"detail": "Valid count value required"}, status=HTTP_400_BAD_REQUEST) if count > MAX_PUSH_COUNT: msg = "Specified count exceeds api limit: {}".format(MAX_PUSH_COUNT) return Response({"detail": msg}, status=HTTP_400_BAD_REQUEST) # we used to have a "full" parameter for this endpoint so you could # specify to not fetch the revision information if it was set to # false. however AFAIK no one ever used it (default was to fetch # everything), so let's just leave it out. it doesn't break # anything to send extra data when not required. pushes = pushes.select_related('repository').prefetch_related('commits')[:count] serializer = PushSerializer(pushes, many=True) meta['count'] = len(pushes) meta['repository'] = project meta['filter_params'] = filter_params resp = { 'meta': meta, 'results': serializer.data } return Response(resp)
def list(self, request, project): """ GET method for list of ``resultset`` records with revisions """ # What is the upper limit on the number of resultsets returned by the api MAX_RESULTS_COUNT = 1000 # make a mutable copy of these params filter_params = request.query_params.copy() # This will contain some meta data about the request and results meta = {} # support ranges for date as well as revisions(changes) like old tbpl for param in ["fromchange", "tochange", "startdate", "enddate", "revision"]: v = filter_params.get(param, None) if v: del(filter_params[param]) meta[param] = v try: repository = Repository.objects.get(name=project) except Repository.DoesNotExist: return Response({ "detail": "No project with name {}".format(project) }, status=HTTP_404_NOT_FOUND) pushes = Push.objects.filter(repository=repository).order_by('-time') for (param, value) in meta.iteritems(): if param == 'fromchange': frompush_time = Push.objects.values_list('time', flat=True).get( repository=repository, revision__startswith=value) pushes = pushes.filter(time__gte=frompush_time) filter_params.update({ "push_timestamp__gte": to_timestamp(frompush_time) }) elif param == 'tochange': topush_time = Push.objects.values_list('time', flat=True).get( repository=repository, revision__startswith=value) pushes = pushes.filter(time__lte=topush_time) filter_params.update({ "push_timestamp__lte": to_timestamp(topush_time) }) elif param == 'startdate': pushes = pushes.filter(time__gte=to_datetime(value)) filter_params.update({ "push_timestamp__gte": to_timestamp(to_datetime(value)) }) elif param == 'enddate': real_end_date = to_datetime(value) + datetime.timedelta(days=1) pushes = pushes.filter(time__lte=real_end_date) filter_params.update({ "push_timestamp__lt": to_timestamp(real_end_date) }) elif param == 'revision': # revision can be either the revision of the push itself, or # any of the commits it refers to pushes = pushes.filter(commits__revision__startswith=value) rev_key = "revisions_long_revision" \ if len(meta['revision']) == 40 else "revisions_short_revision" filter_params.update({rev_key: meta['revision']}) for param in ['push_timestamp__lt', 'push_timestamp__lte', 'push_timestamp__gt', 'push_timestamp__gte']: if filter_params.get(param): # translate push timestamp directly into a filter try: value = datetime.datetime.fromtimestamp( float(filter_params.get(param))) except ValueError: return Response({ "error": "Invalid timestamp specified for {}".format( param) }, status=HTTP_400_BAD_REQUEST) pushes = pushes.filter(**{ param.replace('push_timestamp', 'time'): value }) for param in ['id__lt', 'id__lte', 'id__gt', 'id__gte', 'id']: try: value = int(filter_params.get(param, 0)) except ValueError: return Response({ "error": "Invalid timestamp specified for {}".format( param) }, status=HTTP_400_BAD_REQUEST) if value: pushes = pushes.filter(**{param: value}) id_in = filter_params.get("id__in") if id_in: try: id_in_list = [int(id) for id in id_in.split(',')] except ValueError: return Response({"error": "Invalid id__in specification"}, status=HTTP_400_BAD_REQUEST) pushes = pushes.filter(id__in=id_in_list) author = filter_params.get("author") if author: pushes = pushes.filter(author=author) count = int(filter_params.get("count", 10)) if count > MAX_RESULTS_COUNT: msg = "Specified count exceeds api limit: {}".format(MAX_RESULTS_COUNT) return Response({"error": msg}, status=HTTP_400_BAD_REQUEST) # we used to have a "full" parameter for this endpoint so you could # specify to not fetch the revision information if it was set to # false. however AFAIK no one ever used it (default was to fetch # everything), so let's just leave it out. it doesn't break # anything to send extra data when not required. pushes = pushes.select_related('repository').prefetch_related('commits')[:count] serializer = PushSerializer(pushes, many=True) meta['count'] = len(pushes) meta['repository'] = project meta['filter_params'] = filter_params resp = { 'meta': meta, 'results': serializer.data } return Response(resp)