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 .github/workflows/builders.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.11"]
python-version: ["3.14"]
steps:
- uses: actions/checkout@v5
with:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pylint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.11"]
python-version: ["3.14"]
steps:
- name: Check out code
uses: actions/checkout@v5
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.11"]
python-version: ["3.14"]
steps:

- name: Install bats
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/unit_tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ jobs:
ref: ${{ github.event.pull_request.head.sha }}

- name: Set up Python
uses: actions/setup-python@v2
uses: actions/setup-python@v3
with:
python-version: 3.11
python-version: 3.14

- name: Install dependencies
run: |
Expand Down
8 changes: 4 additions & 4 deletions orion/algorithms/algorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
from typing import Any, Dict, List, Optional, Tuple, Union
import pandas as pd
from tabulate import tabulate
from hunter.report import Report, ReportType
from hunter.series import Series, Metric, ChangePoint, ChangePointGroup
from otava.report import Report, ReportType
from otava.series import Series, Metric, ChangePoint, ChangePointGroup
import orion.constants as cnsts


Expand Down Expand Up @@ -123,7 +123,7 @@ def output_text(self) -> Tuple[str, str, bool]:
for record in data_json:
display_data[display_field].append(str(record.get(display_field, "N/A")))

# Use default Hunter report
# Use default apache_otava report
series, change_points_by_metric = self._analyze()

# Append display_data to series.data in the same format
Expand Down Expand Up @@ -271,7 +271,7 @@ def group_change_points_by_time(

def setup_series(self) -> Series:
"""
Returns hunter.Series
Returns apache_otava.Series
"""
metrics = {
column: Metric(value.get("direction", 1), 1.0)
Expand Down
22 changes: 12 additions & 10 deletions orion/algorithms/cmr/cmr.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
import pandas as pd
import numpy

from hunter.series import ChangePoint, ComparativeStats
from otava.analysis import TTestStats
from otava.series import ChangePoint
from orion.logger import SingletonLogger
from orion.algorithms.algorithm import Algorithm

Expand Down Expand Up @@ -61,15 +62,16 @@ def run_cmr(self, dataframe_list: pd.DataFrame):
for column in metric_columns:

change_point = ChangePoint(metric=column,
index=1,
time=0,
stats=ComparativeStats(
mean_1=dataframe_list[column][0],
mean_2=dataframe_list[column][1],
std_1=0,
std_2=0,
pvalue=1
))
index=1,
qhat=0.0,
time=0,
stats=TTestStats(
mean_1=dataframe_list[column][0],
mean_2=dataframe_list[column][1],
std_1=0.0,
std_2=0.0,
pvalue=1.0
))
change_points_by_metric[column].append(change_point)

# based on change point generate pass/fail
Expand Down
6 changes: 3 additions & 3 deletions orion/algorithms/edivisive/edivisive.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
"""EDivisive Algorithm from hunter"""
"""EDivisive Algorithm from apache_otava"""

# pylint: disable = line-too-long
from typing import Dict, List
import pandas as pd
from hunter.series import ChangePoint
from otava.analysis import ChangePoint
from orion.algorithms.algorithm import Algorithm


class EDivisive(Algorithm):
"""Implementation of the EDivisive algorithm using hunter
"""Implementation of the EDivisive algorithm using apache_otava

Args:
Algorithm (Algorithm): Inherits
Expand Down
24 changes: 13 additions & 11 deletions orion/algorithms/isolationforest/isolationForest.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"""The implementation module for Isolation forest and weighted mean"""
from sklearn.ensemble import IsolationForest
import pandas as pd
from hunter.series import ChangePoint, ComparativeStats
from otava.analysis import TTestStats
from otava.series import ChangePoint
from orion.logger import SingletonLogger
from orion.algorithms.algorithm import Algorithm

Expand Down Expand Up @@ -60,16 +61,17 @@ def _analyze(self):
) * 100
if abs(pct_change) > (10 if self.options.get("min_anomaly_percent",None) is None else int(self.options.get("min_anomaly_percent",None))):
if (pct_change * self.metrics_config[feature]["direction"] > 0) or self.metrics_config[feature]["direction"]==0:
change_point = ChangePoint(metric=feature,
index=idx,
time=row['timestamp'],
stats=ComparativeStats(
mean_1=moving_averages.at[idx, feature],
mean_2=row[feature],
std_1=0,
std_2=0,
pvalue=1
))
change_point = ChangePoint(index=idx,
qhat=0.0,
metric=feature,
time=row['timestamp'],
stats=TTestStats(
mean_1=moving_averages.at[idx, feature],
mean_2=row[feature],
std_1=0.0,
std_2=0.0,
pvalue=1.0
))
change_points_by_metric[feature].append(change_point)
if [val for li in change_points_by_metric.values() for val in li]:
self.regression_flag=True
Expand Down
2 changes: 1 addition & 1 deletion orion/run_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def run(**kwargs: dict[str, Any]) -> Tuple[Tuple[Dict[str, Any], bool, Any, Any,
config (str): file path to config file
es_server (str): elasticsearch endpoint
output_path (str): output path to save the data
hunter_analyze (bool): changepoint detection through hunter. defaults to True
hunter_analyze (bool): changepoint detection through apache_otava. defaults to True
output_format (str): output to be table or json
lookback (str): lookback in days

Expand Down
7 changes: 3 additions & 4 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
hunter @ git+https://github.com/apache/otava.git@v0.5.0
apache-otava @ git+https://github.com/apache/otava.git@3b3d59a787ea03749e972c3509241114b861c99e
click==8.1.7
setuptools_scm>=6.2
elastic-transport==8.11.0
Expand All @@ -7,8 +7,7 @@ opensearch-py==3.0.0
Jinja2==3.1.3
PyYAML==6.0.1
pyshorteners==1.0.1
numpy>=1.24.0,<1.25.0
numpy==2.2.0
scikit-learn==1.5.0
scipy==1.12.0
pandas==2.3.1
tabulate==0.8.10
tabulate==0.9.0
16 changes: 8 additions & 8 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,24 @@
'version_scheme': 'no-guess-dev',
'local_scheme': 'dirty-tag',
},
python_requires='>=3.11,<3.12',
python_requires='>=3.11,<3.15',
setup_requires=['setuptools_scm'],
py_modules=['main', 'version'],
install_requires=[
'click==8.1.7',
'click==8.1.7',
'setuptools_scm>=6.2',
'hunter @ git+https://github.com/apache/[email protected]',
"apache-otava @ \
git+https://github.com/apache/otava.git@3b3d59a787ea03749e972c3509241114b861c99e",
'elastic-transport==8.11.0',
'opensearch-dsl==2.1.0',
'opensearch-py==3.0.0',
'Jinja2==3.1.3',
'PyYAML==6.0.1',
'pyshorteners==1.0.1',
"numpy==1.24.0; python_version=='3.11'",
"numpy==2.2.0; python_version=='3.14'",
'scikit-learn==1.5.0',
'scipy==1.12.0',
"pandas==2.3.1; python_version=='3.11'",
'tabulate==0.8.10',
"pandas==2.3.1; python_version=='3.14'",
'tabulate==0.9.0',
],
entry_points={
'console_scripts': [
Expand All @@ -37,7 +37,7 @@
packages=find_packages(),
license="MIT",
classifiers=[
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.14',
'Operating System :: OS Independent',
],
)
152 changes: 152 additions & 0 deletions test.bats
Original file line number Diff line number Diff line change
Expand Up @@ -541,3 +541,155 @@ setup() {

set -e
}

@test "orion --anomaly-detection with regression should contain inline changepoint" {
set +e
orion --lookback 15d --since 2026-01-20 --anomaly-detection --config hack/ci-tests/ci-tests.yaml --metadata-index "orion-integration-test-data*" --benchmark-index "orion-integration-test-metrics*" --es-server=${QE_ES_SERVER} --node-count true --input-vars='{"version": "4.20"}' > ./outputs/results-anomaly.txt
EXIT_CODE=$?

if [ ! $EXIT_CODE -eq 2 ]; then
echo "no regression found"
exit 1
fi

# Check if the percentage #1 string exists in the output file
if ! grep -q "+155.6%" ./outputs/results-anomaly.txt; then
echo "Expected string '+155.6%' not found in results.txt"
exit 1
fi

# Check if the percentage #2 string exists in the output file
if ! grep -q "+56.7%" ./outputs/results-anomaly.txt; then
echo "Expected string '+56.7%' not found in results.txt"
exit 1
fi

# Check if the percentage #3 string exists in the output file
if ! grep -q "+38.9%" ./outputs/results-anomaly.txt; then
echo "Expected string '+38.9%' not found in results.txt"
exit 1
fi

# Check if the Bad Version string exists in the output file
if ! grep -q "Bad Version: 4.20.0-0.nightly-2026-01-15-195655" ./outputs/results-anomaly.txt; then
echo "Expected string 'Bad Version: 4.20.0-0.nightly-2026-01-15-195655' not found in results.txt"
exit 1
fi

# Check if the Bad Version string exists in the output file
if ! grep -q "Bad Version: 4.20.0-0.nightly-2026-01-17-195655" ./outputs/results-anomaly.txt; then
echo "Expected string 'Bad Version: 4.20.0-0.nightly-2026-01-17-195655' not found in results.txt"
exit 1
fi

set -e
}

@test "orion --anomaly-detection with regression should contain inline changepoint json" {
set +e
orion --lookback 15d --since 2026-01-20 --anomaly-detection --config hack/ci-tests/ci-tests.yaml --metadata-index "orion-integration-test-data*" --benchmark-index "orion-integration-test-metrics*" --es-server=${QE_ES_SERVER} --node-count true --input-vars='{"version": "4.20"}' --output-format json > ./outputs/results-anomaly.json
EXIT_CODE=$?

if [ ! $EXIT_CODE -eq 2 ]; then
echo "no regression found"
exit 1
fi

# Check if changepoints string exists in the output file

$CHANGEPOINTS=$(cat ./outputs/results-anomaly.json | grep '"is_changepoint": true' | wc -l)
if [ ! $CHANGEPOINTS --eq 3 ]; then
echo "Expected number of changepoints not found in ./outputs/results-anomaly.json"
exit 1
fi

set -e
}

@test "orion --anomaly-detection with regression should contain inline changepoint junit" {
set +e
orion --lookback 15d --since 2026-01-20 --anomaly-detection --config hack/ci-tests/ci-tests.yaml --metadata-index "orion-integration-test-data*" --benchmark-index "orion-integration-test-metrics*" --es-server=${QE_ES_SERVER} --node-count true --input-vars='{"version": "4.20"}' --output-format junit > ./outputs/results-anomaly.xml
EXIT_CODE=$?

if [ ! $EXIT_CODE -eq 2 ]; then
echo "no regression found"
exit 1
fi

# Check if the percentage #1 string exists in the output file
if ! grep -q "155.648" ./outputs/results-anomaly.xml; then
echo "Expected string '155.648' not found in ./outputs/results-anomaly.xml"
exit 1
fi

# Check if the percentage #2 string exists in the output file
if ! grep -q "56.7208" ./outputs/results-anomaly.xml; then
echo "Expected string '56.7208' not found in ./outputs/results-anomaly.xml"
exit 1
fi

# Check if the percentage #3 string exists in the output file
if ! grep -q "38.8858" ./outputs/results-anomaly.xml; then
echo "Expected string '38.8858' not found in ./outputs/results-anomaly.xml"
exit 1
fi

set -e
}

@test "orion --cmr with regression should contain inline changepoint" {
set +e
orion --lookback 15d --since 2026-01-20 --cmr --config hack/ci-tests/ci-tests.yaml --metadata-index "orion-integration-test-data*" --benchmark-index "orion-integration-test-metrics*" --es-server=${QE_ES_SERVER} --node-count true --input-vars='{"version": "4.20"}' > ./outputs/results-cmr.txt
EXIT_CODE=$?

if [ ! $EXIT_CODE -eq 0 ]; then
echo "no regression found"
exit 1
fi

# Check if the percentage #1 string exists in the output file
if ! grep -q "+160.9%" ./outputs/results-cmr.txt; then
echo "Expected string '+160.9%' not found in results-cmr.txt"
exit 1
fi

set -e
}

@test "orion --cmr with regression should contain inline changepoint json" {
set +e
orion --lookback 15d --since 2026-01-20 --cmr --config hack/ci-tests/ci-tests.yaml --metadata-index "orion-integration-test-data*" --benchmark-index "orion-integration-test-metrics*" --es-server=${QE_ES_SERVER} --node-count true --input-vars='{"version": "4.20"}' --output-format json > ./outputs/results-cmr.json
EXIT_CODE=$?

if [ ! $EXIT_CODE -eq 0 ]; then
echo "no regression found"
exit 1
fi

bad_version=$(jq -r '.[] | select(.is_changepoint == true) | .ocpVersion' ./outputs/results-cmr.json)
if [ "$bad_version" != "4.20.0-0.nightly-2026-01-18-195655" ]; then
echo "Version did not match. Expected '4.20.0-0.nightly-2026-01-18-195655', got '$bad_version'"
exit 1
fi

set -e
}

@test "orion --cmr with regression should contain inline changepoint junit" {
set +e
orion --lookback 15d --since 2026-01-20 --cmr --config hack/ci-tests/ci-tests.yaml --metadata-index "orion-integration-test-data*" --benchmark-index "orion-integration-test-metrics*" --es-server=${QE_ES_SERVER} --node-count true --input-vars='{"version": "4.20"}' --output-format junit > ./outputs/results-cmr.xml
EXIT_CODE=$?

if [ ! $EXIT_CODE -eq 0 ]; then
echo "no regression found"
exit 1
fi

# Check if the percentage string exists in the output file
if ! grep -q "True | 160.879" ./outputs/results-cmr.xml; then
echo "Expected string 'True | 160.879' not found in results-cmr.xml"
exit 1
fi

set -e
}