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
|
parent: vexxhost-promote-docker-image
|
||||||
vars: *atmosphere_images
|
vars: *atmosphere_images
|
||||||
|
|
||||||
- job:
|
|
||||||
name: atmosphere:linters:tox
|
|
||||||
parent: tox-linters
|
|
||||||
vars:
|
|
||||||
python_version: 3.7
|
|
||||||
|
|
||||||
- project:
|
- project:
|
||||||
check:
|
check:
|
||||||
jobs:
|
jobs:
|
||||||
- atmosphere:linters:tox
|
- tox-linters
|
||||||
- tox-py37
|
- tox-py37
|
||||||
- atmosphere:image:build
|
- atmosphere:image:build
|
||||||
gate:
|
gate:
|
||||||
jobs:
|
jobs:
|
||||||
- atmosphere:linters:tox
|
- tox-linters
|
||||||
- tox-py37
|
- tox-py37
|
||||||
- atmosphere:image:upload
|
- atmosphere:image:upload
|
||||||
promote:
|
promote:
|
||||||
jobs:
|
jobs:
|
||||||
- atmosphere:linters:tox
|
|
||||||
- atmosphere:image:promote
|
- atmosphere:image:promote
|
||||||
|
@ -27,6 +27,7 @@ from flask_migrate import Migrate
|
|||||||
from sqlalchemy import exc
|
from sqlalchemy import exc
|
||||||
from sqlalchemy.orm import exc as orm_exc
|
from sqlalchemy.orm import exc as orm_exc
|
||||||
from sqlalchemy.types import TypeDecorator
|
from sqlalchemy.types import TypeDecorator
|
||||||
|
from sqlalchemy import or_
|
||||||
|
|
||||||
from atmosphere import exceptions
|
from atmosphere import exceptions
|
||||||
|
|
||||||
@ -105,6 +106,34 @@ class Resource(db.Model, GetOrCreateMixin):
|
|||||||
'polymorphic_on': type
|
'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
|
@classmethod
|
||||||
def from_event(cls, event):
|
def from_event(cls, event):
|
||||||
"""from_event"""
|
"""from_event"""
|
||||||
@ -249,7 +278,7 @@ class Period(db.Model):
|
|||||||
ended_at = db.Column(BigIntegerDateTime, index=True)
|
ended_at = db.Column(BigIntegerDateTime, index=True)
|
||||||
|
|
||||||
spec_id = db.Column(db.Integer, db.ForeignKey('spec.id'), nullable=False)
|
spec_id = db.Column(db.Integer, db.ForeignKey('spec.id'), nullable=False)
|
||||||
spec = db.relationship("Spec")
|
spec = db.relationship("Spec", lazy='joined')
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def seconds(self):
|
def seconds(self):
|
||||||
|
@ -42,6 +42,7 @@ def ignored_event(request):
|
|||||||
def app():
|
def app():
|
||||||
app = create_app()
|
app = create_app()
|
||||||
app.config['TESTING'] = True
|
app.config['TESTING'] = True
|
||||||
|
app.config['SQLALCHEMY_ECHO'] = True
|
||||||
app.register_blueprint(ingress.blueprint)
|
app.register_blueprint(ingress.blueprint)
|
||||||
return app
|
return app
|
||||||
|
|
||||||
|
@ -64,6 +64,139 @@ class GetOrCreateTestMixin:
|
|||||||
class TestResource(GetOrCreateTestMixin):
|
class TestResource(GetOrCreateTestMixin):
|
||||||
MODEL = models.Resource
|
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):
|
def test_from_event(self):
|
||||||
event = fake.get_normalized_event()
|
event = fake.get_normalized_event()
|
||||||
resource = models.Resource.from_event(event)
|
resource = models.Resource.from_event(event)
|
||||||
|
Loading…
Reference in New Issue
Block a user