Skip to content

Commit

Permalink
feature(frontend): Adding support for dynamic TracetestAPI instance (#…
Browse files Browse the repository at this point in the history
…3075)

* feature(frontend): Adding support for dynamic TracetestAPI instance

* feature(frontend): Adding support for dynamic TracetestAPI instance

* Tenant ID queries fix

* Removing test for the moment

* Cleanup and test fixing
  • Loading branch information
xoscar committed Aug 18, 2023
1 parent ab8f000 commit 0bb4286
Show file tree
Hide file tree
Showing 87 changed files with 1,060 additions and 1,037 deletions.
6 changes: 0 additions & 6 deletions node_modules/.package-lock.json

This file was deleted.

6 changes: 0 additions & 6 deletions package-lock.json

This file was deleted.

37 changes: 33 additions & 4 deletions server/executor/queue.go
Expand Up @@ -10,6 +10,7 @@ import (

"github.com/kubeshop/tracetest/server/datastore"
"github.com/kubeshop/tracetest/server/executor/pollingprofile"
"github.com/kubeshop/tracetest/server/http/middleware"
"github.com/kubeshop/tracetest/server/pkg/id"
"github.com/kubeshop/tracetest/server/subscription"
"github.com/kubeshop/tracetest/server/test"
Expand Down Expand Up @@ -277,6 +278,10 @@ func (q *Queue) SetDriver(driver QueueDriver) {
driver.SetQueue(q)
}

func propagator() propagation.TextMapPropagator {
return propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}, tenantPropagator{})
}

func (q Queue) Enqueue(ctx context.Context, job Job) {
select {
default:
Expand All @@ -287,8 +292,7 @@ func (q Queue) Enqueue(ctx context.Context, job Job) {
if job.Headers == nil {
job.Headers = &headers{}
}
propagator := propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{})
propagator.Inject(ctx, propagation.MapCarrier(*job.Headers))
propagator().Inject(ctx, propagation.MapCarrier(*job.Headers))

newJob := Job{
Headers: job.Headers,
Expand All @@ -308,8 +312,7 @@ func (q Queue) Enqueue(ctx context.Context, job Job) {

func (q Queue) Listen(job Job) {
// this is called when a new job is put in the queue and we need to process it
propagator := propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{})
ctx := propagator.Extract(context.Background(), propagation.MapCarrier(*job.Headers))
ctx := propagator().Extract(context.Background(), propagation.MapCarrier(*job.Headers))

ctx, cancelCtx := context.WithCancel(ctx)
q.listenForStopRequests(context.Background(), cancelCtx, job)
Expand Down Expand Up @@ -470,3 +473,29 @@ func (q Queue) resolveDataStore(ctx context.Context, job Job) datastore.DataStor

return ds
}

type tenantPropagator struct{}

var _ propagation.TextMapPropagator = tenantPropagator{}

func (b tenantPropagator) Inject(ctx context.Context, carrier propagation.TextMapCarrier) {
tenantID := middleware.TenantIDFromContext(ctx)
if tenantID != "" {
carrier.Set(string(middleware.TenantIDKey), tenantID)
}
}

// Extract returns a copy of parent with the baggage from the carrier added.
func (b tenantPropagator) Extract(parent context.Context, carrier propagation.TextMapCarrier) context.Context {
tenantID := carrier.Get(string(middleware.TenantIDKey))
if tenantID == "" {
return parent
}

return context.WithValue(parent, middleware.TenantIDKey, tenantID)
}

// Fields returns the keys who's values are set with Inject.
func (b tenantPropagator) Fields() []string {
return []string{string(middleware.TenantIDKey)}
}
1 change: 0 additions & 1 deletion server/http/controller.go
Expand Up @@ -261,7 +261,6 @@ func (c *controller) RunTest(ctx context.Context, testID string, runInfo openapi
requiredGates := c.mappers.In.RequiredGates(runInfo.RequiredGates)

run := c.testRunner.Run(ctx, test, metadata(runInfo.Metadata), environment, requiredGates)

return openapi.Response(200, c.mappers.Out.Run(&run)), nil
}

Expand Down
10 changes: 10 additions & 0 deletions server/http/middleware/tenant.go
Expand Up @@ -42,3 +42,13 @@ func isValidUUID(value string) bool {
_, err := uuid.Parse(value)
return err == nil
}

func TenantIDFromContext(ctx context.Context) string {
tenantID := ctx.Value(TenantIDKey)

if tenantID == nil {
return ""
}

return tenantID.(string)
}
6 changes: 3 additions & 3 deletions server/pkg/sqlutil/tenant.go
Expand Up @@ -19,7 +19,7 @@ func Tenant(ctx context.Context, query string, params ...any) (string, []any) {
paramNumber := len(params) + 1
condition := fmt.Sprintf(" %s tenant_id = $%d", prefix, paramNumber)

return query + condition, append(params, tenantID)
return query + condition, append(params, *tenantID)
}

func TenantWithPrefix(ctx context.Context, query string, prefix string, params ...any) (string, []any) {
Expand All @@ -30,9 +30,9 @@ func TenantWithPrefix(ctx context.Context, query string, prefix string, params .

queryPrefix := getQueryPrefix(query)
paramNumber := len(params) + 1
condition := fmt.Sprintf(" %s %stenant_id = $%d)", queryPrefix, prefix, paramNumber)
condition := fmt.Sprintf(" %s %stenant_id = $%d", queryPrefix, prefix, paramNumber)

return query + condition, append(params, tenantID)
return query + condition, append(params, *tenantID)
}

func TenantID(ctx context.Context) *string {
Expand Down
12 changes: 6 additions & 6 deletions server/test/run_repository.go
Expand Up @@ -384,7 +384,7 @@ FROM
`

func (r *runRepository) GetRun(ctx context.Context, testID id.ID, runID int) (Run, error) {
query, params := sqlutil.Tenant(ctx, selectRunQuery+" WHERE id = $1 AND test_id = $2", runID, testID)
query, params := sqlutil.TenantWithPrefix(ctx, selectRunQuery+" WHERE id = $1 AND test_id = $2", "test_runs.", runID, testID)

run, err := readRunRow(r.db.QueryRowContext(ctx, query, params...))
if err != nil {
Expand All @@ -394,7 +394,7 @@ func (r *runRepository) GetRun(ctx context.Context, testID id.ID, runID int) (Ru
}

func (r *runRepository) GetTestRuns(ctx context.Context, test Test, take, skip int32) ([]Run, error) {
query, params := sqlutil.Tenant(ctx, selectRunQuery+" WHERE test_id = $1", test.ID, take, skip)
query, params := sqlutil.TenantWithPrefix(ctx, selectRunQuery+" WHERE test_id = $1", "test_runs.", test.ID, take, skip)
stmt, err := r.db.Prepare(query + " ORDER BY created_at DESC LIMIT $2 OFFSET $3")
if err != nil {
return []Run{}, err
Expand Down Expand Up @@ -430,8 +430,8 @@ func (r *runRepository) GetRunByTraceID(ctx context.Context, traceID trace.Trace
}

func (r *runRepository) GetLatestRunByTestVersion(ctx context.Context, testID id.ID, version int) (Run, error) {
query, params := sqlutil.Tenant(ctx, selectRunQuery+" WHERE test_id = $1 AND test_version = $2 ORDER BY created_at DESC LIMIT 1", testID.String(), version)
stmt, err := r.db.Prepare(query)
query, params := sqlutil.TenantWithPrefix(ctx, selectRunQuery+" WHERE test_id = $1 AND test_version = $2", "test_runs.", testID.String(), version)
stmt, err := r.db.Prepare(query + " ORDER BY created_at DESC LIMIT 1")

if err != nil {
return Run{}, err
Expand Down Expand Up @@ -601,9 +601,9 @@ func readRunRow(row scanner) (Run, error) {
func (r *runRepository) GetTestSuiteRunSteps(ctx context.Context, id id.ID, runID int) ([]Run, error) {
query := selectRunQuery + `
WHERE test_suite_run_steps.test_suite_run_id = $1 AND test_suite_run_steps.test_suite_run_test_suite_id = $2
ORDER BY test_runs.completed_at ASC
`
query, params := sqlutil.Tenant(ctx, query, strconv.Itoa(runID), id)
query, params := sqlutil.TenantWithPrefix(ctx, query, "test_runs.", strconv.Itoa(runID), id)
query += ` ORDER BY test_runs.completed_at ASC`

stmt, err := r.db.Prepare(query)
if err != nil {
Expand Down
8 changes: 4 additions & 4 deletions server/test/test_repository.go
Expand Up @@ -193,7 +193,7 @@ func (r *repository) GetAugmented(ctx context.Context, id id.ID) (Test, error) {
const sortQuery = `ORDER BY t.version DESC LIMIT 1`

func (r *repository) get(ctx context.Context, id id.ID) (Test, error) {
query, params := sqlutil.Tenant(ctx, getTestSQL+" WHERE t.id = $1", id)
query, params := sqlutil.TenantWithPrefix(ctx, getTestSQL+" WHERE t.id = $1", "t.", id)

test, err := r.readRow(ctx, r.db.QueryRowContext(ctx, query+sortQuery, params...))
if err != nil {
Expand All @@ -205,8 +205,8 @@ func (r *repository) get(ctx context.Context, id id.ID) (Test, error) {

func (r *repository) GetTestSuiteSteps(ctx context.Context, id id.ID, version int) ([]Test, error) {
sortQuery := `ORDER BY ts.step_number ASC`
query, params := sqlutil.Tenant(ctx, getTestSQL+testMaxVersionQuery+` INNER JOIN test_suite_steps ts ON t.id = ts.test_id
WHERE ts.test_suite_id = $1 AND ts.test_suite_version = $2`, id, version)
query, params := sqlutil.TenantWithPrefix(ctx, getTestSQL+testMaxVersionQuery+` INNER JOIN test_suite_steps ts ON t.id = ts.test_id
WHERE ts.test_suite_id = $1 AND ts.test_suite_version = $2`, "t.", id, version)
stmt, err := r.db.Prepare(query + sortQuery)
if err != nil {
return []Test{}, fmt.Errorf("prepare 2: %w", err)
Expand Down Expand Up @@ -566,7 +566,7 @@ func (r *repository) Exists(ctx context.Context, id id.ID) (bool, error) {
}

func (r *repository) GetVersion(ctx context.Context, id id.ID, version int) (Test, error) {
query, params := sqlutil.Tenant(ctx, getTestSQL+" WHERE t.id = $1 AND t.version = $2", id, version)
query, params := sqlutil.TenantWithPrefix(ctx, getTestSQL+" WHERE t.id = $1 AND t.version = $2", "t.", id, version)
stmt, err := r.db.Prepare(query)
if err != nil {
return Test{}, fmt.Errorf("prepare: %w", err)
Expand Down
8 changes: 4 additions & 4 deletions server/testsuite/testsuite_repository.go
Expand Up @@ -272,7 +272,7 @@ func (r *Repository) Get(ctx context.Context, id id.ID) (TestSuite, error) {
}

func (r *Repository) get(ctx context.Context, id id.ID, augmented bool) (TestSuite, error) {
query, params := sqlutil.Tenant(ctx, querySelect()+" WHERE t.id = $1", id)
query, params := sqlutil.TenantWithPrefix(ctx, querySelect()+" WHERE t.id = $1", "t.", id)
stmt, err := r.db.Prepare(query + "ORDER BY t.version DESC LIMIT 1")
if err != nil {
return TestSuite{}, fmt.Errorf("prepare: %w", err)
Expand All @@ -288,7 +288,7 @@ func (r *Repository) get(ctx context.Context, id id.ID, augmented bool) (TestSui
}

func (r *Repository) GetVersion(ctx context.Context, id id.ID, version int) (TestSuite, error) {
query, params := sqlutil.Tenant(ctx, querySelect()+" WHERE t.id = $1 AND t.version = $2", id, version)
query, params := sqlutil.TenantWithPrefix(ctx, querySelect()+" WHERE t.id = $1 AND t.version = $2", "t.", id, version)
stmt, err := r.db.Prepare(query)
if err != nil {
return TestSuite{}, fmt.Errorf("prepare 1: %w", err)
Expand All @@ -309,13 +309,13 @@ func listQuery(ctx context.Context, baseSQL, query string, params []any) (string

sql := baseSQL + testSuiteMaxVersionQuery
sql, params = sqlutil.Search(sql, condition, query, params)
sql, params = sqlutil.Tenant(ctx, sql, params...)
sql, params = sqlutil.TenantWithPrefix(ctx, sql, "t.", params...)

return sql, params
}

func (r *Repository) GetLatestVersion(ctx context.Context, id id.ID) (TestSuite, error) {
query, params := sqlutil.Tenant(ctx, querySelect()+" WHERE t.id = $1", id)
query, params := sqlutil.TenantWithPrefix(ctx, querySelect()+" WHERE t.id = $1", "t.", id)
stmt, err := r.db.Prepare(query + " ORDER BY t.version DESC LIMIT 1")
if err != nil {
return TestSuite{}, fmt.Errorf("prepare: %w", err)
Expand Down
2 changes: 1 addition & 1 deletion server/testsuite/testsuite_run_repository.go
Expand Up @@ -364,7 +364,7 @@ func (td *RunRepository) GetLatestRunByTestSuiteVersion(ctx context.Context, ID
}

func (td *RunRepository) GetTestSuiteRuns(ctx context.Context, ID id.ID, take, skip int32) ([]TestSuiteRun, error) {
sortQuery := "ORDER BY created_at DESC LIMIT $2 OFFSET $3"
sortQuery := " ORDER BY created_at DESC LIMIT $2 OFFSET $3"
query, params := sqlutil.Tenant(ctx, selectTestSuiteRunQuery+" WHERE test_suite_id = $1", ID.String(), take, skip)
stmt, err := td.db.Prepare(query + sortQuery)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion server/variableset/variableset_repository.go
Expand Up @@ -142,10 +142,10 @@ func (r *Repository) List(ctx context.Context, take, skip int, query, sortBy, so
"name": "e.name",
}

sql, params = sqlutil.TenantWithPrefix(ctx, sql, "e.", params...)
sql = sqlutil.Sort(sql, sortBy, sortDirection, "created", sortingFields)
sql += ` LIMIT $1 OFFSET $2 `

sql, params = sqlutil.Tenant(ctx, sql, params...)
stmt, err := r.db.Prepare(sql)
if err != nil {
return []VariableSet{}, err
Expand Down
2 changes: 1 addition & 1 deletion web/cypress/e2e/TestSuites/TestSuite.spec.ts
Expand Up @@ -4,7 +4,7 @@ const testSuiteUtils = TestSuite();

describe('TestSuites', () => {
beforeEach(() => {
cy.visit('/');
cy.visit('/testsuites');
cy.wrap(testSuiteUtils.createTests());
});

Expand Down
2 changes: 1 addition & 1 deletion web/cypress/e2e/TestSuites/TestSuiteRun.spec.ts
Expand Up @@ -4,7 +4,7 @@ const testSuitesUtils = TestSuites();

describe('TestSuiteRuns', () => {
beforeEach(() => {
cy.visit('/');
cy.visit('/testsuites');
cy.wrap(testSuitesUtils.createTests());
});

Expand Down
11 changes: 5 additions & 6 deletions web/cypress/support/commands.ts
Expand Up @@ -48,7 +48,6 @@ Cypress.Commands.add('deleteTest', (shouldIntercept = false) => {

Cypress.Commands.add('openTestCreationModal', () => {
cy.get('[data-cy=create-button]').click();
cy.get('.test-create-selector-items ul li').first().click();
cy.get('[data-cy=create-test-steps-CreateTestFactory]').should('be.visible');
});

Expand All @@ -63,7 +62,8 @@ Cypress.Commands.add('interceptEditTestCall', () => {
});

Cypress.Commands.add('interceptHomeApiCall', () => {
cy.intercept({method: 'GET', url: '/api/resources?take=20&skip=0*'}).as('testList');
cy.intercept({method: 'GET', url: '/api/tests?take=20&skip=0*'}).as('testList');
cy.intercept({method: 'GET', url: '/api/testsuites?take=20&skip=0*'}).as('testSuitesList');
cy.intercept({method: 'DELETE', url: '/api/tests/**'}).as('testDelete');
cy.intercept({method: 'POST', url: '/api/tests'}).as('testCreation');
cy.intercept({method: 'DELETE', url: '/api/testsuites/**'}).as('testSuiteDelete');
Expand Down Expand Up @@ -232,24 +232,23 @@ Cypress.Commands.add('selectRunDetailMode', (index: number) => {

Cypress.Commands.add('openTestSuiteCreationModal', () => {
cy.get('[data-cy=create-button]').click();
cy.get('.ant-dropdown-menu-item').last().click();
cy.get('[data-cy=create-test-steps-CreateTestSuiteFactory]').should('be.visible');
});

Cypress.Commands.add('deleteTestSuite', () => {
cy.location('pathname').then(pathname => {
const localTestId = getTestSuiteId(pathname);

cy.visit(`/`);
cy.wait('@testList');
cy.visit(`/testsuites`);
cy.wait('@testSuitesList');
cy.get('[data-cy=test-list]').should('exist', {timeout: 10000});
cy.get(`[data-cy=test-actions-button-${localTestId}]`, {timeout: 10000}).should('be.visible');
cy.get(`[data-cy=test-actions-button-${localTestId}]`).click({force: true});
cy.get('[data-cy=test-card-delete]').click();
cy.get('[data-cy=confirmation-modal] .ant-btn-primary').click();
cy.wait('@testSuiteDelete');
cy.get(`[data-cy=test-actions-button-${localTestId}]`).should('not.exist');
cy.wait('@testList');
cy.wait('@testSuitesList');
cy.clearLocalStorage();
});
});
Expand Down
4 changes: 3 additions & 1 deletion web/src/components/Editor/hooks/useTooltip.ts
@@ -1,6 +1,8 @@
import {useCallback, useState} from 'react';
import {TResolveExpressionContext, TResolveRequestInfo} from 'types/Expression.types';
import {useParseExpressionMutation} from 'redux/apis/Tracetest';
import TracetestAPI from 'redux/apis/Tracetest';

const {useParseExpressionMutation} = TracetestAPI.instance;

const useTooltip = (context: TResolveExpressionContext = {}) => {
const [parseExpressionMutation, {isLoading}] = useParseExpressionMutation();
Expand Down
@@ -1,7 +1,7 @@
import {capitalize, noop} from 'lodash';
import {noop} from 'lodash';
import {createContext, useCallback, useContext, useMemo, useState} from 'react';
import FileViewerModal from 'components/FileViewerModal';
import {ResourceType} from 'types/Resource.type';
import {ResourceName, ResourceType} from 'types/Resource.type';
import useDefinitionFile from 'hooks/useDefinitionFile';
import useJUnitResult from 'hooks/useJUnitResult';

Expand Down Expand Up @@ -61,7 +61,7 @@ const FileViewerModalProvider = ({children}: IProps) => {
setIsFileViewerOpen(true);
loadDefinition(resourceType, resourceId, version);
setProps({
title: `${capitalize(resourceType)} Definition`,
title: `${ResourceName[resourceType]} Definition`,
language: 'yaml',
subtitle: 'Preview your YAML file',
fileName: `${resourceType}-${resourceId}-${version || 0}-definition.yaml`,
Expand Down
1 change: 1 addition & 0 deletions web/src/components/Layout/Layout.styled.ts
Expand Up @@ -14,6 +14,7 @@ export const Content = styled(LayoutAntd.Content)<{$hasMenu: boolean}>`
`;

export const Layout = styled(LayoutAntd)`
min-height: 100%;
background: ${({theme}) => theme.color.background};
`;

Expand Down
8 changes: 7 additions & 1 deletion web/src/components/Layout/Layout.tsx
Expand Up @@ -26,10 +26,16 @@ const menuItems = [
key: '0',
icon: <ClusterOutlined />,
label: <Link to="/">Tests</Link>,
path: '/',
path: '/tests',
},
{
key: '1',
icon: <ClusterOutlined />,
label: <Link to="/testsuites">Test Suites</Link>,
path: '/testsuites',
},
{
key: '2',
icon: <GlobalOutlined />,
label: <Link to="/variablesets">Variable Sets</Link>,
path: '/variablesets',
Expand Down
4 changes: 3 additions & 1 deletion web/src/components/ResourceCard/TestCard.tsx
@@ -1,7 +1,7 @@
import {DownOutlined, RightOutlined} from '@ant-design/icons';
import {useMemo} from 'react';
import TestRunCard from 'components/RunCard/TestRunCard';
import {useLazyGetRunListQuery} from 'redux/apis/Tracetest';
import TracetestAPI from 'redux/apis/Tracetest';
import {ResourceType} from 'types/Resource.type';
import Test from 'models/Test.model';
import TestRun from 'models/TestRun.model';
Expand All @@ -11,6 +11,8 @@ import ResourceCardRuns from './ResourceCardRuns';
import ResourceCardSummary from './ResourceCardSummary';
import useRuns from './useRuns';

const {useLazyGetRunListQuery} = TracetestAPI.instance;

interface IProps {
onEdit(id: string, lastRunId: number, type: ResourceType): void;
onDelete(id: string, name: string, type: ResourceType): void;
Expand Down

0 comments on commit 0bb4286

Please sign in to comment.