Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion api/v1/charts.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def _get_connector(self, args, source):
return MinioConnector(**args)
else:
if source == "errors":
log.info('Using LokiConnector')
log.info('Using LokiConnector %s', args)
return LokiConnector(**args)
elif source == "engine_health":
project_id = Report.query.with_entities(Report.project_id).filter(
Expand Down
11 changes: 6 additions & 5 deletions connectors/loki_connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import Optional

import requests

Expand All @@ -22,11 +23,11 @@

class LokiConnector:

def __init__(self, **args) -> None:
self.test_name = args['test_name']
self.query_range_url = LokiLogFetcher.make_url() # todo: here we should consider making url from project
self.start_time, self.end_time = timeframe(args, time_as_ts=True)

def __init__(self, *, test_name: str, project_id: Optional[int] = None, **kwargs) -> None:
self.test_name = test_name
self.query_range_url = LokiLogFetcher.make_url(project_id) # todo: here we should consider making url from project
kwargs['test_name'] = self.test_name
self.start_time, self.end_time = timeframe(kwargs, time_as_ts=True)

def get_issues(self) -> list:
data = {
Expand Down
13 changes: 3 additions & 10 deletions models/pd/quality_gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@ class QualityGateSLA(BaseModel):
checked: bool


class QualityGateBaseline(BaseModel):
checked: bool
rt_baseline_comparison_mecric: str
class QualityGateBaseline(QualityGateSLA):
rt_baseline_comparison_metric: str


class QualityGateSettingsSummary(BaseModel):
Expand All @@ -19,13 +18,7 @@ class QualityGateSettingsSummary(BaseModel):
throughput_deviation: PositiveInt


class QualityGateSettingsRequests(BaseModel):
check_response_time: bool
response_time_deviation: PositiveInt
check_error_rate: bool
error_rate_deviation: conint(ge=0, le=100)
check_throughput: bool
throughput_deviation: PositiveInt
class QualityGateSettingsRequests(QualityGateSettingsSummary):
percentage_of_failed_requests: conint(ge=0, le=100)


Expand Down
36 changes: 18 additions & 18 deletions models/pd/thresholds.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Optional
from typing import Optional, Literal
from pydantic import BaseModel, validator, AnyUrl, parse_obj_as, root_validator, constr

from ..tests import Test
Expand All @@ -10,9 +10,9 @@ class ThresholdPD(BaseModel):
test: str
environment: str
scope: str
target: str
aggregation: str
comparison: str
target: Literal['throughput', 'error_rate', 'response_time']
aggregation: Literal['max', 'min', 'avg', 'pct95', 'pct50']
comparison: Literal['gte', 'lte', 'lt', 'gt', 'eq']
value: float

@validator('test')
Expand Down Expand Up @@ -42,17 +42,17 @@ def validate_scope_exists(cls, value: str, values: dict):
).first(), 'Such scope does not exist'
return value

@validator('target')
def validate_target(cls, value: str):
assert value in {'throughput', 'error_rate', 'response_time'}, f'Target {value} is not supported'
return value

@validator('aggregation')
def validate_aggregation(cls, value: str):
assert value in {'max', 'min', 'avg', 'pct95', 'pct50'}, f'Aggregation {value} is not supported'
return value

@validator('comparison')
def validate_comparison(cls, value: str):
assert value in {'gte', 'lte', 'lt', 'gt', 'eq'}, f'Comparison {value} is not supported'
return value
# @validator('target')
# def validate_target(cls, value: str):
# assert value in {'throughput', 'error_rate', 'response_time'}, f'Target {value} is not supported'
# return value
#
# @validator('aggregation')
# def validate_aggregation(cls, value: str):
# assert value in {'max', 'min', 'avg', 'pct95', 'pct50'}, f'Aggregation {value} is not supported'
# return value
#
# @validator('comparison')
# def validate_comparison(cls, value: str):
# assert value in {'gte', 'lte', 'lt', 'gt', 'eq'}, f'Comparison {value} is not supported'
# return value
5 changes: 5 additions & 0 deletions slots/results.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ def content(self, context, slot, payload):
result_id = payload.request.args.get('result_id')
if result_id:
report = Report.query.get_or_404(result_id)
if not self.context.rpc_manager.call.admin_check_user_in_project(
project_id=report.project_id,
user_id=payload.auth.id
):
return theme.access_denied_part
test_data = report.to_json()
test_data["is_baseline_report"] = report.is_baseline_report
try:
Expand Down
15 changes: 8 additions & 7 deletions static/js/backend_performance.js
Original file line number Diff line number Diff line change
Expand Up @@ -371,16 +371,17 @@ const TestCreateModal = {
<slot name='sources'></slot>

<div class="form-group mt-3">
<div class="form-group">
<p class="font-h5 font-semibold">Entrypoint</p>
<p class="font-h6 font-weight-400">File for jMeter and class for gatling</p>
<input type="text" class="form-control form-control-alternative mt-2"
<label class="d-block">
<p class="font-h5 font-semibold">Entrypoint</p>
<p class="font-h6 font-weight-400">File for jMeter and class for gatling</p>
<input type="text" class="form-control form-control-alternative mt-2"
placeholder="Entrypoint (e.g. some.jmx or some.Test)"
name="backend_entrypoint"
v-model='entrypoint'
:class="{ 'is-invalid': errors?.entrypoint }"
>
<div class="invalid-feedback">[[ get_error_msg('entrypoint') ]]</div>
</div>
>
<div class="invalid-feedback">[[ get_error_msg('entrypoint') ]]</div>
</label>
</div>
</div>
</div>
Expand Down
5 changes: 4 additions & 1 deletion static/js/chart_legend.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const ChartLegend = {
components: {
LegendItem: LegendItem
},
props: ['chart_object_name', 'select_all_enabled', 'item_container_classes'],
props: ['chart_object_name', 'select_all_enabled', 'item_container_classes', 'chart_data_loaded'],
data() {
return {
all_selected: true,
Expand Down Expand Up @@ -52,6 +52,9 @@ const ChartLegend = {
this.handle_chart_changes(i)
})
this.chart_object.update()
},
chart_data_loaded(new_value) {
new_value && this.reload()
}
},
template: `
Expand Down
18 changes: 9 additions & 9 deletions static/js/quality_gate.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,15 @@ const QualityGate = {
request_error_rate_deviation,
request_throughput_deviation,
percentage_of_failed_requests,
rt_baseline_comparison_mecric,
rt_baseline_comparison_metric,
} = this
return {
SLA: {
checked: SLA
},
baseline: {
checked: baseline,
rt_baseline_comparison_mecric: rt_baseline_comparison_mecric
rt_baseline_comparison_metric: rt_baseline_comparison_metric
},
settings: {
summary_results: {
Expand Down Expand Up @@ -91,7 +91,7 @@ const QualityGate = {
request_error_rate_deviation: data.settings.per_request_results.error_rate_deviation,
request_throughput_deviation: data.settings.per_request_results.throughput_deviation,
percentage_of_failed_requests: data.settings.per_request_results.percentage_of_failed_requests,
rt_baseline_comparison_mecric: data.baseline.rt_baseline_comparison_mecric
rt_baseline_comparison_metric: data.baseline.rt_baseline_comparison_metric
}
Object.assign(this.$data, {...this.initialState(), ...data_to_load})
},
Expand Down Expand Up @@ -120,8 +120,8 @@ const QualityGate = {
request_error_rate_deviation: 1,
request_throughput_deviation: 1,
percentage_of_failed_requests: 20,
rt_baseline_comparison_mecric: "pct95",
is_adv_settins_open: false,
rt_baseline_comparison_metric: "pct95",
is_adv_settings_open: false,
errors: {},

})
Expand Down Expand Up @@ -151,12 +151,12 @@ const QualityGate = {
role="button"
aria-expanded="false"
aria-controls="selector_advanced_settings"
@click="is_adv_settins_open = !is_adv_settins_open"
@click="is_adv_settings_open = !is_adv_settings_open"
>
<div>
<p class="font-h6 font-semibold text-gray-600">ADVANCED SETTINGS
<button class="btn btn-nooutline-secondary p-0 pb-1 ml-1 collapsed">
<i class="icon__16x16 icon-arrow-down__16" :class="is_adv_settins_open ? '' : 'rotate-270'"></i>
<i class="icon__16x16 icon-arrow-down__16" :class="is_adv_settings_open ? '' : 'rotate-270'"></i>
</button>
</p>
</div>
Expand Down Expand Up @@ -335,14 +335,14 @@ const QualityGate = {
</div>
<div class="col mb-2 d-flex flex-column w-100">
<select class="selectpicker bootstrap-select__b" data-style="btn"
v-model="rt_baseline_comparison_mecric">
v-model="rt_baseline_comparison_metric">
<option value="max">Maximum</option>
<option value="min">Minimum</option>
<option value="avg">Average</option>
<option value="pct95">Percentile 95</option>
<option value="pct50">Percentile 50</option>
</select>
<div class="invalid-feedback" style="display: block;">[[ errors.baseline_rt_baseline_comparison_mecric ]]</div>
<div class="invalid-feedback" style="display: block;">[[ errors.baseline_rt_baseline_comparison_metric ]]</div>
</div>
</div>

Expand Down
8 changes: 4 additions & 4 deletions static/js/results.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,13 @@ const SummaryController = {
samplers: [],
sampler_type: 'REQUEST',
status_type: 'all',
// todo: change to 'auto'
// aggregator: '30s',
aggregator: 'auto',
update_interval: 0,
auto_update_id: null,
status_percentage: 0,
active_tab_id: undefined,
current_chart: 'presetLine'
current_chart: 'presetLine',
chart_data_loaded: false
}
},
async mounted() {
Expand Down Expand Up @@ -250,6 +249,7 @@ const SummaryController = {
}
},
async load_request_data(url, y_label) {
this.chart_data_loaded = false
$('#chart-loader').show();
const $preset = $("#preset")
if (!$preset.is(":visible")) {
Expand Down Expand Up @@ -281,11 +281,11 @@ const SummaryController = {
window.presetLine.data = data
window.presetLine.update()
}

$('#chart-loader').hide();
} else {
// todo: handle fetch error
}
this.chart_data_loaded = true
},
handle_download(event) {
console.log('todo handle download')
Expand Down
3 changes: 2 additions & 1 deletion templates/results/summary.html
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,9 @@
<Chart-Legend
@register="register"
instance_name="requests_chart_legend"
:chart_object_name="master.current_chart"
item_container_classes="custom-chart-legend"
:chart_object_name="master.current_chart"
:chart_data_loaded="master.chart_data_loaded"
></Chart-Legend>
</div>
</div>
Expand Down
16 changes: 9 additions & 7 deletions utils/report_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@
from collections import defaultdict
from datetime import datetime, timezone
from typing import Tuple, Union, Optional, List
from pydantic import BaseModel, validator, ValidationError

from tools import data_tools, MinioClient, rpc_tools
from influxdb.exceptions import InfluxDBClientError
from pydantic import BaseModel, validator, ValidationError

from pylon.core.tools import log

from ..models.baselines import Baseline
from ..models.reports import Report
# from influxdb.exceptions import InfluxDBClientError

from tools import data_tools, MinioClient, rpc_tools


def _create_dataset_for_users(timeline, data, scope, metric, axe):
Expand Down Expand Up @@ -290,6 +291,7 @@ def timeframe(args: dict, time_as_ts: bool = False) -> tuple:


def delete_project_reports(project: Union['Project', int], report_ids: List[int]) -> None:
from ..connectors.influx_connector import InfluxConnector
if isinstance(project, int):
project = rpc_tools.RpcMixin().rpc.call.project_get_or_404(
project_id=project)
Expand All @@ -305,10 +307,10 @@ def delete_project_reports(project: Union['Project', int], report_ids: List[int]
minio_delete_build_ids = dict()
for build_id, name, lg_type, test_config in query_result:
# delete influx tables
# try:
# InfluxConnector(build_id=build_id, test_name=name, lg_type=lg_type).delete_test_data()
# except InfluxDBClientError as e:
# log.warning('InfluxDBClientError %s', e)
try:
InfluxConnector(build_id=build_id, test_name=name, lg_type=lg_type).delete_test_data()
except InfluxDBClientError as e:
log.warning('InfluxDBClientError %s', e)

# collect s3 data for deletion
s3_settings = test_config.get(
Expand Down