Added get_all_by_time_range
This method will allow retrieving resources with number of seconds used, which should be the last step before exposing the actual API. Change-Id: Iba7b074eeb34e127818953491626d6edb54dfdd1
This commit is contained in:
parent
ebbb899953
commit
d5f060ad09
11
.zuul.yaml
11
.zuul.yaml
@ -19,24 +19,17 @@
|
||||
parent: vexxhost-promote-docker-image
|
||||
vars: *atmosphere_images
|
||||
|
||||
- job:
|
||||
name: atmosphere:linters:tox
|
||||
parent: tox-linters
|
||||
vars:
|
||||
python_version: 3.7
|
||||
|
||||
- project:
|
||||
check:
|
||||
jobs:
|
||||
- atmosphere:linters:tox
|
||||
- tox-linters
|
||||
- tox-py37
|
||||
- atmosphere:image:build
|
||||
gate:
|
||||
jobs:
|
||||
- atmosphere:linters:tox
|
||||
- tox-linters
|
||||
- tox-py37
|
||||
- atmosphere:image:upload
|
||||
promote:
|
||||
jobs:
|
||||
- atmosphere:linters:tox
|
||||
- atmosphere:image:promote
|
||||
|
@ -27,6 +27,7 @@ from flask_migrate import Migrate
|
||||
from sqlalchemy import exc
|
||||
from sqlalchemy.orm import exc as orm_exc
|
||||
from sqlalchemy.types import TypeDecorator
|
||||
from sqlalchemy import or_
|
||||
|
||||
from atmosphere import exceptions
|
||||
|
||||
@ -105,6 +106,34 @@ class Resource(db.Model, GetOrCreateMixin):
|
||||
'polymorphic_on': type
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def get_all_by_time_range(cls, start, end, project=None):
|
||||
"""Get all resources given a specific period."""
|
||||
query = cls.query.join(Period).filter(
|
||||
# Resources must have started before the end
|
||||
Period.started_at <= end,
|
||||
# Resources must be still active or ended after start
|
||||
or_(
|
||||
Period.ended_at >= start,
|
||||
Period.ended_at.is_(None)
|
||||
),
|
||||
)
|
||||
|
||||
if project is not None:
|
||||
query = query.filter(Resource.project == project)
|
||||
|
||||
resources = query.all()
|
||||
for resource in resources:
|
||||
for period in resource.periods:
|
||||
db.session.expunge(period)
|
||||
if period.started_at <= start:
|
||||
period.started_at = start
|
||||
if period.ended_at is None or period.ended_at >= end:
|
||||
period.ended_at = end
|
||||
resource.periods = [p for p in resource.periods if p.seconds != 0]
|
||||
|
||||
return resources
|
||||
|
||||
@classmethod
|
||||
def from_event(cls, event):
|
||||
"""from_event"""
|
||||
@ -249,7 +278,7 @@ class Period(db.Model):
|
||||
ended_at = db.Column(BigIntegerDateTime, index=True)
|
||||
|
||||
spec_id = db.Column(db.Integer, db.ForeignKey('spec.id'), nullable=False)
|
||||
spec = db.relationship("Spec")
|
||||
spec = db.relationship("Spec", lazy='joined')
|
||||
|
||||
@property
|
||||
def seconds(self):
|
||||
|
@ -42,6 +42,7 @@ def ignored_event(request):
|
||||
def app():
|
||||
app = create_app()
|
||||
app.config['TESTING'] = True
|
||||
app.config['SQLALCHEMY_ECHO'] = True
|
||||
app.register_blueprint(ingress.blueprint)
|
||||
return app
|
||||
|
||||
|
@ -64,6 +64,139 @@ class GetOrCreateTestMixin:
|
||||
class TestResource(GetOrCreateTestMixin):
|
||||
MODEL = models.Resource
|
||||
|
||||
def test_get_all_by_time_range_with_no_data(self):
|
||||
start = datetime.datetime.now()
|
||||
ended = start + relativedelta(hours=+1)
|
||||
data = models.Resource.get_all_by_time_range(start, ended)
|
||||
|
||||
assert len(data) == 0
|
||||
|
||||
def test_get_all_by_time_range_by_project(self):
|
||||
event = fake.get_normalized_event()
|
||||
resource = models.Resource.get_or_create(event)
|
||||
|
||||
start = event['traits']['created_at'] - relativedelta(hours=+1)
|
||||
ended = start + relativedelta(hours=+2)
|
||||
|
||||
data = models.Resource.get_all_by_time_range(start, ended,
|
||||
project="project")
|
||||
assert len(data) == 0
|
||||
|
||||
data = models.Resource.get_all_by_time_range(start, ended,
|
||||
project="fake-project")
|
||||
assert len(data) == 1
|
||||
assert data[0].periods[0].seconds == 3600
|
||||
|
||||
def test_get_all_by_time_range_with_resource_ended_before_start(self):
|
||||
event = fake.get_normalized_event()
|
||||
event['traits']['deleted_at'] = event['traits']['created_at'] + \
|
||||
relativedelta(hours=+1)
|
||||
|
||||
resource = models.Resource.get_or_create(event)
|
||||
|
||||
start = event['traits']['deleted_at'] + relativedelta(hours=+1)
|
||||
ended = start + relativedelta(hours=+1)
|
||||
data = models.Resource.get_all_by_time_range(start, ended)
|
||||
|
||||
assert len(data) == 0
|
||||
|
||||
def test_get_all_by_time_range_with_resource_started_after_end(self):
|
||||
event = fake.get_normalized_event()
|
||||
resource = models.Resource.get_or_create(event)
|
||||
|
||||
ended = event['traits']['created_at'] - relativedelta(hours=+1)
|
||||
start = ended - relativedelta(hours=+1)
|
||||
data = models.Resource.get_all_by_time_range(start, ended)
|
||||
|
||||
assert len(data) == 0
|
||||
|
||||
def test_get_all_by_time_range_with_active_resource_after_start(self):
|
||||
event = fake.get_normalized_event()
|
||||
resource = models.Resource.get_or_create(event)
|
||||
|
||||
start = event['traits']['created_at'] - relativedelta(hours=+1)
|
||||
ended = start + relativedelta(hours=+2)
|
||||
data = models.Resource.get_all_by_time_range(start, ended)
|
||||
|
||||
assert len(data) == 1
|
||||
assert data[0].periods[0].seconds == 3600
|
||||
|
||||
def test_get_all_by_time_range_with_active_resource_before_start(self):
|
||||
event = fake.get_normalized_event()
|
||||
resource = models.Resource.get_or_create(event)
|
||||
|
||||
start = event['traits']['created_at'] + relativedelta(minutes=+30)
|
||||
ended = start + relativedelta(minutes=+30)
|
||||
data = models.Resource.get_all_by_time_range(start, ended)
|
||||
|
||||
assert len(data) == 1
|
||||
assert data[0].periods[0].seconds == 1800
|
||||
|
||||
def test_get_all_by_time_range_with_active_resource_after_end(self):
|
||||
event = fake.get_normalized_event()
|
||||
event['traits']['deleted_at'] = event['traits']['created_at'] + \
|
||||
relativedelta(hours=+1)
|
||||
|
||||
resource = models.Resource.get_or_create(event)
|
||||
|
||||
start = event['traits']['deleted_at'] + relativedelta(hours=+1)
|
||||
ended = start + relativedelta(hours=+2)
|
||||
data = models.Resource.get_all_by_time_range(start, ended)
|
||||
|
||||
assert len(data) == 0
|
||||
|
||||
def test_get_all_by_time_range_with_resource_inside_range(self):
|
||||
event = fake.get_normalized_event()
|
||||
event['traits']['deleted_at'] = event['traits']['created_at'] + \
|
||||
relativedelta(minutes=+15)
|
||||
|
||||
resource = models.Resource.get_or_create(event)
|
||||
|
||||
start = event['traits']['created_at'] - relativedelta(hours=+1)
|
||||
ended = start + relativedelta(hours=+2)
|
||||
data = models.Resource.get_all_by_time_range(start, ended)
|
||||
|
||||
assert len(data) == 1
|
||||
assert data[0].periods[0].seconds == 900
|
||||
|
||||
def test_get_all_by_time_range_with_resource_with_multiple_periods(self):
|
||||
event = fake.get_normalized_event()
|
||||
event['traits']['created_at'] = event['traits']['created_at'] + \
|
||||
relativedelta(microseconds=0)
|
||||
models.Resource.get_or_create(event)
|
||||
|
||||
event['generated'] = event['traits']['created_at'] + \
|
||||
relativedelta(minutes=+15, microseconds=0)
|
||||
event['traits']['instance_type'] = 'v2-standard-8'
|
||||
models.Resource.get_or_create(event)
|
||||
|
||||
start = event['traits']['created_at'] - relativedelta(hours=+1)
|
||||
ended = start + relativedelta(hours=+2)
|
||||
data = models.Resource.get_all_by_time_range(start, ended)
|
||||
|
||||
assert len(data) == 1
|
||||
assert data[0].periods[0].seconds == 900
|
||||
assert data[0].periods[1].seconds == 2700
|
||||
|
||||
def test_get_all_by_time_range_with_resource_with_one_active_period(self):
|
||||
event = fake.get_normalized_event()
|
||||
event['traits']['created_at'] = event['traits']['created_at'] + \
|
||||
relativedelta(microseconds=0)
|
||||
models.Resource.get_or_create(event)
|
||||
|
||||
event['generated'] = event['traits']['created_at'] + \
|
||||
relativedelta(minutes=+15, microseconds=0)
|
||||
event['traits']['instance_type'] = 'v2-standard-8'
|
||||
models.Resource.get_or_create(event)
|
||||
|
||||
start = event['traits']['created_at'] + relativedelta(minutes=+15)
|
||||
ended = start + relativedelta(minutes=+45)
|
||||
data = models.Resource.get_all_by_time_range(start, ended)
|
||||
|
||||
assert len(data) == 1
|
||||
assert len(data[0].periods) == 1
|
||||
assert data[0].periods[0].seconds == 2700
|
||||
|
||||
def test_from_event(self):
|
||||
event = fake.get_normalized_event()
|
||||
resource = models.Resource.from_event(event)
|
||||
|
Loading…
Reference in New Issue
Block a user