mirror of
https://github.com/SigNoz/signoz.git
synced 2026-08-14 00:40:35 +01:00
Compare commits
2 Commits
main
...
fix/clear-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb41877f21 | ||
|
|
5e0c9208d7 |
@@ -274,6 +274,15 @@ func (store *store) SoftDeleteUser(ctx context.Context, orgID string, id string)
|
||||
return errors.Wrapf(err, errors.TypeInternal, errors.CodeInternal, "failed to delete tokens")
|
||||
}
|
||||
|
||||
// delete user_role assignments so the roles can be deleted later
|
||||
_, err = tx.NewDelete().
|
||||
Model(new(authtypes.UserRole)).
|
||||
Where("user_id = ?", id).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, errors.TypeInternal, errors.CodeInternal, "failed to delete user roles")
|
||||
}
|
||||
|
||||
// soft delete user
|
||||
now := time.Now()
|
||||
_, err = tx.NewUpdate().
|
||||
|
||||
@@ -3104,19 +3104,7 @@ func (aH *APIHandler) PreviewLogsPipelinesHandler(w http.ResponseWriter, r *http
|
||||
return
|
||||
}
|
||||
|
||||
claims, errv2 := authtypes.ClaimsFromContext(r.Context())
|
||||
if errv2 != nil {
|
||||
render.Error(w, errv2)
|
||||
return
|
||||
}
|
||||
|
||||
orgID, errv2 := valuer.NewUUID(claims.OrgID)
|
||||
if errv2 != nil {
|
||||
render.Error(w, errv2)
|
||||
return
|
||||
}
|
||||
|
||||
resultLogs, err := aH.LogsParsingPipelineController.PreviewLogsPipelines(r.Context(), orgID, &req)
|
||||
resultLogs, err := aH.LogsParsingPipelineController.PreviewLogsPipelines(r.Context(), &req)
|
||||
if err != nil {
|
||||
render.Error(w, err)
|
||||
return
|
||||
|
||||
@@ -342,7 +342,6 @@ type PipelinesPreviewResponse struct {
|
||||
|
||||
func (ic *LogParsingPipelineController) PreviewLogsPipelines(
|
||||
ctx context.Context,
|
||||
orgID valuer.UUID,
|
||||
request *PipelinesPreviewRequest,
|
||||
) (*PipelinesPreviewResponse, error) {
|
||||
pipelines, err := ic.enrichPipelinesFilters(ctx, request.Pipelines)
|
||||
@@ -350,11 +349,6 @@ func (ic *LogParsingPipelineController) PreviewLogsPipelines(
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// The collector gets the same pipeline prepended over opamp; see RecommendAgentConfig.
|
||||
if ic.fl.BooleanOrEmpty(ctx, flagger.FeatureUseJSONBody, featuretypes.NewFlaggerEvaluationContext(orgID)) {
|
||||
pipelines = append([]pipelinetypes.GettablePipeline{ic.getNormalizePipeline()}, pipelines...)
|
||||
}
|
||||
|
||||
result, collectorLogs, err := SimulatePipelinesProcessing(ctx, pipelines, request.Logs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -6,14 +6,11 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/flagger/flaggertest"
|
||||
"github.com/SigNoz/signoz/pkg/query-service/model"
|
||||
v3 "github.com/SigNoz/signoz/pkg/query-service/model/v3"
|
||||
"github.com/SigNoz/signoz/pkg/types/pipelinetypes"
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
"github.com/google/uuid"
|
||||
"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/entry"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
@@ -21,7 +18,39 @@ func TestPipelinePreview(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
testPipelines := []pipelinetypes.GettablePipeline{
|
||||
makeTestAddAttributePipeline(),
|
||||
{
|
||||
StoreablePipeline: pipelinetypes.StoreablePipeline{
|
||||
OrderID: 1,
|
||||
Name: "pipeline1",
|
||||
Alias: "pipeline1",
|
||||
Enabled: true,
|
||||
},
|
||||
Filter: &v3.FilterSet{
|
||||
Operator: "AND",
|
||||
Items: []v3.FilterItem{
|
||||
{
|
||||
Key: v3.AttributeKey{
|
||||
Key: "method",
|
||||
DataType: v3.AttributeKeyDataTypeString,
|
||||
Type: v3.AttributeKeyTypeTag,
|
||||
},
|
||||
Operator: "=",
|
||||
Value: "GET",
|
||||
},
|
||||
},
|
||||
},
|
||||
Config: []pipelinetypes.PipelineOperator{
|
||||
{
|
||||
OrderId: 1,
|
||||
ID: "add",
|
||||
Type: "add",
|
||||
Field: "attributes.test",
|
||||
Value: "val",
|
||||
Enabled: true,
|
||||
Name: "test add",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
StoreablePipeline: pipelinetypes.StoreablePipeline{
|
||||
OrderID: 2,
|
||||
@@ -119,93 +148,6 @@ func TestPipelinePreview(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func TestPipelinePreviewNormalizesBodyWithJSONBodyEnabled(t *testing.T) {
|
||||
controller := &LogParsingPipelineController{fl: flaggertest.WithUseJSONBody(t, true)}
|
||||
|
||||
result, err := controller.PreviewLogsPipelines(
|
||||
context.Background(),
|
||||
valuer.GenerateUUID(),
|
||||
&PipelinesPreviewRequest{
|
||||
Pipelines: []pipelinetypes.GettablePipeline{makeTestAddAttributePipeline()},
|
||||
Logs: []model.SignozLog{
|
||||
makeTestSignozLog("test log body", map[string]interface{}{"method": "GET"}),
|
||||
makeTestSignozLog(
|
||||
`{"level":"error","msg":"json log body"}`,
|
||||
map[string]interface{}{"method": "GET"},
|
||||
),
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Len(t, result.OutputLogs, 2)
|
||||
|
||||
assert.Equal(t, `{"message":"test log body"}`, result.OutputLogs[0].Body)
|
||||
assert.Equal(
|
||||
t,
|
||||
`{"level":"error","message":"json log body"}`,
|
||||
result.OutputLogs[1].Body,
|
||||
)
|
||||
assert.Equal(t, "val", result.OutputLogs[0].Attributes_string["test"])
|
||||
}
|
||||
|
||||
func TestPipelinePreviewKeepsBodyAsIsWithJSONBodyDisabled(t *testing.T) {
|
||||
controller := &LogParsingPipelineController{fl: flaggertest.WithUseJSONBody(t, false)}
|
||||
|
||||
result, err := controller.PreviewLogsPipelines(
|
||||
context.Background(),
|
||||
valuer.GenerateUUID(),
|
||||
&PipelinesPreviewRequest{
|
||||
Pipelines: []pipelinetypes.GettablePipeline{makeTestAddAttributePipeline()},
|
||||
Logs: []model.SignozLog{
|
||||
makeTestSignozLog("test log body", map[string]interface{}{"method": "GET"}),
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Len(t, result.OutputLogs, 1)
|
||||
|
||||
assert.Equal(t, "test log body", result.OutputLogs[0].Body)
|
||||
assert.Equal(t, "val", result.OutputLogs[0].Attributes_string["test"])
|
||||
}
|
||||
|
||||
func makeTestAddAttributePipeline() pipelinetypes.GettablePipeline {
|
||||
return pipelinetypes.GettablePipeline{
|
||||
StoreablePipeline: pipelinetypes.StoreablePipeline{
|
||||
OrderID: 1,
|
||||
Name: "pipeline1",
|
||||
Alias: "pipeline1",
|
||||
Enabled: true,
|
||||
},
|
||||
Filter: &v3.FilterSet{
|
||||
Operator: "AND",
|
||||
Items: []v3.FilterItem{
|
||||
{
|
||||
Key: v3.AttributeKey{
|
||||
Key: "method",
|
||||
DataType: v3.AttributeKeyDataTypeString,
|
||||
Type: v3.AttributeKeyTypeTag,
|
||||
},
|
||||
Operator: "=",
|
||||
Value: "GET",
|
||||
},
|
||||
},
|
||||
},
|
||||
Config: []pipelinetypes.PipelineOperator{
|
||||
{
|
||||
OrderId: 1,
|
||||
ID: "add",
|
||||
Type: "add",
|
||||
Field: "attributes.test",
|
||||
Value: "val",
|
||||
Enabled: true,
|
||||
Name: "test add",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestGrokParsingProcessor(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
|
||||
@@ -240,6 +240,7 @@ func NewSQLMigrationProviderFactories(
|
||||
sqlmigration.NewFixSavedViewSelectedFieldsFactory(sqlstore),
|
||||
sqlmigration.NewBackfillSavedViewRequestTypeFactory(sqlstore),
|
||||
sqlmigration.NewRestructureAuthDomainConfigFactory(sqlstore),
|
||||
sqlmigration.NewDeleteOrphanUserRolesFactory(),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
65
pkg/sqlmigration/114_delete_orphan_user_roles.go
Normal file
65
pkg/sqlmigration/114_delete_orphan_user_roles.go
Normal file
@@ -0,0 +1,65 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/types"
|
||||
"github.com/SigNoz/signoz/pkg/types/authtypes"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type deleteOrphanUserRoles struct{}
|
||||
|
||||
func NewDeleteOrphanUserRolesFactory() factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(
|
||||
factory.MustNewName("delete_orphan_user_roles"),
|
||||
func(ctx context.Context, ps factory.ProviderSettings, c Config) (SQLMigration, error) {
|
||||
return &deleteOrphanUserRoles{}, nil
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func (migration *deleteOrphanUserRoles) Register(migrations *migrate.Migrations) error {
|
||||
return migrations.Register(migration.Up, migration.Down)
|
||||
}
|
||||
|
||||
func (migration *deleteOrphanUserRoles) Up(ctx context.Context, db *bun.DB) error {
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
var deletedUserIDs []string
|
||||
err = tx.NewSelect().
|
||||
Model(new(types.User)).
|
||||
Column("id").
|
||||
Where("status = ?", types.UserStatusDeleted).
|
||||
Scan(ctx, &deletedUserIDs)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(deletedUserIDs) == 0 {
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
_, err = tx.NewDelete().
|
||||
Model(new(authtypes.UserRole)).
|
||||
Where("user_id IN (?)", bun.In(deletedUserIDs)).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
func (migration *deleteOrphanUserRoles) Down(context.Context, *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
@@ -123,6 +123,23 @@ func (b *StatementBuilder) Build(
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO(srikanthccv): move the missing-key detection into the where clause
|
||||
// visitor. Doing it here over the lexer-derived selectors can't tell a key
|
||||
// from a value, so dashboard variables and bare literals in value position
|
||||
// (e.g. `service.name = $service`) get flagged as missing keys. We still add
|
||||
// a labels fallback for any unresolved selector so the query can be built,
|
||||
// but we no longer emit a warning until the visitor can classify keys.
|
||||
for _, sel := range keySelectors {
|
||||
if _, ok := keys[sel.Name]; !ok {
|
||||
keys[sel.Name] = []*telemetrytypes.TelemetryFieldKey{{
|
||||
Name: sel.Name,
|
||||
FieldContext: telemetrytypes.FieldContextAttribute,
|
||||
FieldDataType: telemetrytypes.FieldDataTypeString,
|
||||
Signal: telemetrytypes.SignalMetrics,
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
||||
start, end = querybuilder.AdjustedMetricTimeRange(start, end, uint64(query.StepInterval.Seconds()), query)
|
||||
|
||||
return b.buildPipelineStatement(ctx, orgID, start, end, query, keys, variables)
|
||||
@@ -162,10 +179,9 @@ func (b *StatementBuilder) buildPipelineStatement(
|
||||
|
||||
var timeSeriesCTE string
|
||||
var timeSeriesCTEArgs []any
|
||||
var filterWarnings []string
|
||||
var err error
|
||||
|
||||
if timeSeriesCTE, timeSeriesCTEArgs, filterWarnings, err = b.buildTimeSeriesCTE(ctx, orgID, tsStart, tsEnd, cteQuery, keys, variables, tsTable); err != nil {
|
||||
if timeSeriesCTE, timeSeriesCTEArgs, err = b.buildTimeSeriesCTE(ctx, orgID, tsStart, tsEnd, cteQuery, keys, variables, tsTable); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -220,7 +236,6 @@ func (b *StatementBuilder) buildPipelineStatement(
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mainStmt.Warnings = append(mainStmt.Warnings, filterWarnings...)
|
||||
if reducedFragments == nil {
|
||||
return mainStmt, nil
|
||||
}
|
||||
@@ -468,7 +483,7 @@ func (b *StatementBuilder) buildTimeSeriesCTE(
|
||||
keys map[string][]*telemetrytypes.TelemetryFieldKey,
|
||||
variables map[string]qbtypes.VariableItem,
|
||||
tsTable string,
|
||||
) (string, []any, []string, error) {
|
||||
) (string, []any, error) {
|
||||
sb := sqlbuilder.NewSelectBuilder()
|
||||
|
||||
var preparedWhereClause querybuilder.PreparedWhereClause
|
||||
@@ -488,7 +503,7 @@ func (b *StatementBuilder) buildTimeSeriesCTE(
|
||||
EndNs: end,
|
||||
})
|
||||
if err != nil {
|
||||
return "", nil, nil, err
|
||||
return "", nil, err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -498,7 +513,7 @@ func (b *StatementBuilder) buildTimeSeriesCTE(
|
||||
for i, g := range query.GroupBy {
|
||||
col, err := b.fm.ColumnExpressionFor(ctx, orgID, start, end, &g.TelemetryFieldKey, telemetrytypes.FieldDataTypeString, keys)
|
||||
if err != nil {
|
||||
return "", nil, nil, err
|
||||
return "", nil, err
|
||||
}
|
||||
sb.SelectMore(fmt.Sprintf("%s AS `%s`", sqlbuilder.Escape(col), GroupByColumnAlias(i, g.Name)))
|
||||
}
|
||||
@@ -527,7 +542,7 @@ func (b *StatementBuilder) buildTimeSeriesCTE(
|
||||
sb.GroupBy(GroupByAliases(query.GroupBy)...)
|
||||
|
||||
q, args := sb.BuildWithFlavor(sqlbuilder.ClickHouse)
|
||||
return fmt.Sprintf("(%s) AS filtered_time_series", q), args, preparedWhereClause.Warnings, nil
|
||||
return fmt.Sprintf("(%s) AS filtered_time_series", q), args, nil
|
||||
}
|
||||
|
||||
func (b *StatementBuilder) buildTemporalAggregationCTE(
|
||||
|
||||
@@ -316,9 +316,8 @@ func TestStatementBuilder(t *testing.T) {
|
||||
},
|
||||
},
|
||||
expected: qbtypes.Statement{
|
||||
Query: "WITH __temporal_aggregation_cte AS (SELECT ts, `__GROUP_BY_KEY_0_k8s.statefulset.name`, multiIf(row_number() OVER rate_window = 1, nan, (per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) < 0, per_series_value / (ts - lagInFrame(ts, 1) OVER rate_window), (per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) / (ts - lagInFrame(ts, 1) OVER rate_window)) AS per_series_value FROM (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(30)) AS ts, `__GROUP_BY_KEY_0_k8s.statefulset.name`, max(value) AS per_series_value FROM signoz_metrics.distributed_samples_v4 AS points INNER JOIN (SELECT fingerprint, JSONExtractString(labels, 'k8s.statefulset.name') AS `__GROUP_BY_KEY_0_k8s.statefulset.name` FROM signoz_metrics.time_series_v4_6hrs WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND LOWER(temporality) LIKE LOWER(?) AND JSONExtractString(labels, 'k8s.statefulset.name') = ? GROUP BY fingerprint, `__GROUP_BY_KEY_0_k8s.statefulset.name`) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY fingerprint, ts, `__GROUP_BY_KEY_0_k8s.statefulset.name` ORDER BY fingerprint, ts) WINDOW rate_window AS (PARTITION BY fingerprint ORDER BY fingerprint, ts)), __spatial_aggregation_cte AS (SELECT ts, `__GROUP_BY_KEY_0_k8s.statefulset.name`, sum(per_series_value) AS value FROM __temporal_aggregation_cte WHERE isNaN(per_series_value) = ? GROUP BY ts, `__GROUP_BY_KEY_0_k8s.statefulset.name`) SELECT * FROM __spatial_aggregation_cte ORDER BY `__GROUP_BY_KEY_0_k8s.statefulset.name`, ts",
|
||||
Args: []any{"signoz_calls_total", uint64(1747936800000), uint64(1747983420000), "cumulative", "my-statefulset", "signoz_calls_total", uint64(1747947360000), uint64(1747983420000), 0},
|
||||
Warnings: []string{"label `k8s.statefulset.name` not found in metadata; check the label name for typos"},
|
||||
Query: "WITH __temporal_aggregation_cte AS (SELECT ts, `__GROUP_BY_KEY_0_k8s.statefulset.name`, multiIf(row_number() OVER rate_window = 1, nan, (per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) < 0, per_series_value / (ts - lagInFrame(ts, 1) OVER rate_window), (per_series_value - lagInFrame(per_series_value, 1) OVER rate_window) / (ts - lagInFrame(ts, 1) OVER rate_window)) AS per_series_value FROM (SELECT fingerprint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), toIntervalSecond(30)) AS ts, `__GROUP_BY_KEY_0_k8s.statefulset.name`, max(value) AS per_series_value FROM signoz_metrics.distributed_samples_v4 AS points INNER JOIN (SELECT fingerprint, JSONExtractString(labels, 'k8s.statefulset.name') AS `__GROUP_BY_KEY_0_k8s.statefulset.name` FROM signoz_metrics.time_series_v4_6hrs WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli <= ? AND LOWER(temporality) LIKE LOWER(?) AND JSONExtractString(labels, 'k8s.statefulset.name') = ? GROUP BY fingerprint, `__GROUP_BY_KEY_0_k8s.statefulset.name`) AS filtered_time_series ON points.fingerprint = filtered_time_series.fingerprint WHERE metric_name IN (?) AND unix_milli >= ? AND unix_milli < ? GROUP BY fingerprint, ts, `__GROUP_BY_KEY_0_k8s.statefulset.name` ORDER BY fingerprint, ts) WINDOW rate_window AS (PARTITION BY fingerprint ORDER BY fingerprint, ts)), __spatial_aggregation_cte AS (SELECT ts, `__GROUP_BY_KEY_0_k8s.statefulset.name`, sum(per_series_value) AS value FROM __temporal_aggregation_cte WHERE isNaN(per_series_value) = ? GROUP BY ts, `__GROUP_BY_KEY_0_k8s.statefulset.name`) SELECT * FROM __spatial_aggregation_cte ORDER BY `__GROUP_BY_KEY_0_k8s.statefulset.name`, ts",
|
||||
Args: []any{"signoz_calls_total", uint64(1747936800000), uint64(1747983420000), "cumulative", "my-statefulset", "signoz_calls_total", uint64(1747947360000), uint64(1747983420000), 0},
|
||||
},
|
||||
expectedErr: nil,
|
||||
},
|
||||
|
||||
@@ -129,4 +129,4 @@ def test_delete_user(
|
||||
assert response.status_code == HTTPStatus.OK
|
||||
data = response.json()["data"]
|
||||
assert data["status"] == "deleted"
|
||||
assert len(data["userRoles"]) == 1
|
||||
assert len(data["userRoles"]) == 0
|
||||
|
||||
@@ -175,9 +175,8 @@ def test_metrics_filter_unknown_label_matches_nothing(
|
||||
insert_metrics: Callable[[list[Metrics]], None],
|
||||
) -> None:
|
||||
"""A filter on a label no metric carries resolves to JSONExtractString(labels,'<missing>')
|
||||
= '' and matches nothing: metrics returns 200 with an empty result, and warns that the
|
||||
label is absent from metadata. Only keys are flagged — a value or dashboard variable in
|
||||
value position never reaches the condition builder, so it cannot be mistaken for one."""
|
||||
= '' and matches nothing: metrics returns 200 with an empty result and — unlike the
|
||||
logs/traces synthesize path — emits no key-not-found warning."""
|
||||
now = datetime.now(tz=UTC).replace(second=0, microsecond=0)
|
||||
insert_metrics(
|
||||
[
|
||||
@@ -209,7 +208,7 @@ def test_metrics_filter_unknown_label_matches_nothing(
|
||||
)
|
||||
assert response.status_code == HTTPStatus.OK, response.text
|
||||
assert querier.get_scalar_table_data(response.json()) == []
|
||||
assert [w["message"] for w in querier.get_all_warnings(response.json())] == ["label `does_not_exist_label` not found in metadata; check the label name for typos"]
|
||||
assert querier.get_all_warnings(response.json()) == []
|
||||
|
||||
|
||||
def test_metrics_full_text_filter_does_not_error(
|
||||
|
||||
@@ -267,6 +267,40 @@ def test_delete_role_with_assignee_guarded(
|
||||
assert resp.status_code == HTTPStatus.NO_CONTENT, resp.text
|
||||
|
||||
|
||||
def test_delete_role_after_deleting_assigned_user(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: types.Operation, # pylint: disable=unused-argument
|
||||
get_token: Callable[[str, str], str],
|
||||
create_role: Callable[..., str],
|
||||
):
|
||||
admin_token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
|
||||
role_id = create_role(admin_token, "crud-deleted-assignee-role", [transaction_group("read", "metaresource", "dashboard", ["*"])])
|
||||
|
||||
user_id = create_active_user(
|
||||
signoz,
|
||||
admin_token,
|
||||
email="crud+deleted-assignee@integration.test",
|
||||
role="signoz-viewer",
|
||||
password=CRUD_ASSIGNEE_USER_PASSWORD,
|
||||
name="crud-deleted-assignee-user",
|
||||
)
|
||||
|
||||
resp = requests.post(
|
||||
signoz.self.host_configs["8080"].get("/api/v2/user_roles"),
|
||||
json={"userId": user_id, "roleId": role_id},
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
timeout=5,
|
||||
)
|
||||
assert resp.status_code == HTTPStatus.CREATED, resp.text
|
||||
|
||||
resp = requests.delete(signoz.self.host_configs["8080"].get(f"/api/v2/users/{user_id}"), headers={"Authorization": f"Bearer {admin_token}"}, timeout=5)
|
||||
assert resp.status_code == HTTPStatus.NO_CONTENT, resp.text
|
||||
|
||||
resp = requests.delete(signoz.self.host_configs["8080"].get(f"/api/v1/roles/{role_id}"), headers={"Authorization": f"Bearer {admin_token}"}, timeout=5)
|
||||
assert resp.status_code == HTTPStatus.NO_CONTENT, f"delete role after deleting its only assignee: {resp.text}"
|
||||
|
||||
|
||||
def test_delete_removes_role(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: types.Operation, # pylint: disable=unused-argument
|
||||
|
||||
Reference in New Issue
Block a user