feat: Add more telemetry to free AI credits feature (no-changelog) (#12493)

This commit is contained in:
Ricardo Espinoza
2025-01-08 02:20:45 -05:00
committed by GitHub
parent 6f00c74c1f
commit b1d17f5201
9 changed files with 341 additions and 6 deletions

View File

@@ -2,7 +2,7 @@ import { mock } from 'jest-mock-extended';
import { v5 as uuidv5, v3 as uuidv3, v4 as uuidv4, v1 as uuidv1 } from 'uuid';
import { STICKY_NODE_TYPE } from '@/Constants';
import { ApplicationError } from '@/errors';
import { ApplicationError, ExpressionError, NodeApiError } from '@/errors';
import type { IRun, IRunData } from '@/Interfaces';
import { NodeConnectionType, type IWorkflowBase } from '@/Interfaces';
import * as nodeHelpers from '@/NodeHelpers';
@@ -12,6 +12,7 @@ import {
generateNodesGraph,
getDomainBase,
getDomainPath,
userInInstanceRanOutOfFreeAiCredits,
} from '@/TelemetryHelpers';
import { randomInt } from '@/utils';
@@ -930,6 +931,227 @@ describe('extractLastExecutedNodeCredentialData', () => {
});
});
describe('userInInstanceRanOutOfFreeAiCredits', () => {
it('should return false if could not find node credentials', () => {
const runData = {
status: 'error',
mode: 'manual',
data: {
startData: {
destinationNode: 'OpenAI',
runNodeFilter: ['OpenAI'],
},
executionData: {
nodeExecutionStack: [{ node: { credentials: {} } }],
},
resultData: {
runData: {},
lastNodeExecuted: 'OpenAI',
error: new NodeApiError(
{
id: '1',
typeVersion: 1,
name: 'OpenAI',
type: 'n8n-nodes-base.openAi',
parameters: {},
position: [100, 200],
},
{
message: `400 - ${JSON.stringify({
error: {
message: 'error message',
type: 'free_ai_credits_request_error',
code: 200,
},
})}`,
error: {
message: 'error message',
type: 'free_ai_credits_request_error',
code: 200,
},
},
{
httpCode: '400',
},
),
},
},
} as unknown as IRun;
expect(userInInstanceRanOutOfFreeAiCredits(runData)).toBe(false);
});
it('should return false if could not credential type it is not openAiApi', () => {
const runData = {
status: 'error',
mode: 'manual',
data: {
startData: {
destinationNode: 'OpenAI',
runNodeFilter: ['OpenAI'],
},
executionData: {
nodeExecutionStack: [{ node: { credentials: { jiraApi: { id: 'nhu-l8E4hX' } } } }],
},
resultData: {
runData: {},
lastNodeExecuted: 'OpenAI',
error: new NodeApiError(
{
id: '1',
typeVersion: 1,
name: 'OpenAI',
type: 'n8n-nodes-base.openAi',
parameters: {},
position: [100, 200],
},
{
message: `400 - ${JSON.stringify({
error: {
message: 'error message',
type: 'free_ai_credits_request_error',
code: 200,
},
})}`,
error: {
message: 'error message',
type: 'free_ai_credits_request_error',
code: 200,
},
},
{
httpCode: '400',
},
),
},
},
} as unknown as IRun;
expect(userInInstanceRanOutOfFreeAiCredits(runData)).toBe(false);
});
it('should return false if error is not NodeApiError', () => {
const runData = {
status: 'error',
mode: 'manual',
data: {
startData: {
destinationNode: 'OpenAI',
runNodeFilter: ['OpenAI'],
},
executionData: {
nodeExecutionStack: [{ node: { credentials: { openAiApi: { id: 'nhu-l8E4hX' } } } }],
},
resultData: {
runData: {},
lastNodeExecuted: 'OpenAI',
error: new ExpressionError('error'),
},
},
} as unknown as IRun;
expect(userInInstanceRanOutOfFreeAiCredits(runData)).toBe(false);
});
it('should return false if error is not a free ai credit error', () => {
const runData = {
status: 'error',
mode: 'manual',
data: {
startData: {
destinationNode: 'OpenAI',
runNodeFilter: ['OpenAI'],
},
executionData: {
nodeExecutionStack: [{ node: { credentials: { openAiApi: { id: 'nhu-l8E4hX' } } } }],
},
resultData: {
runData: {},
lastNodeExecuted: 'OpenAI',
error: new NodeApiError(
{
id: '1',
typeVersion: 1,
name: 'OpenAI',
type: 'n8n-nodes-base.openAi',
parameters: {},
position: [100, 200],
},
{
message: `400 - ${JSON.stringify({
error: {
message: 'error message',
type: 'error_type',
code: 200,
},
})}`,
error: {
message: 'error message',
type: 'error_type',
code: 200,
},
},
{
httpCode: '400',
},
),
},
},
} as unknown as IRun;
expect(userInInstanceRanOutOfFreeAiCredits(runData)).toBe(false);
});
it('should return true if the user has ran out of free AI credits', () => {
const runData = {
status: 'error',
mode: 'manual',
data: {
startData: {
destinationNode: 'OpenAI',
runNodeFilter: ['OpenAI'],
},
executionData: {
nodeExecutionStack: [{ node: { credentials: { openAiApi: { id: 'nhu-l8E4hX' } } } }],
},
resultData: {
runData: {},
lastNodeExecuted: 'OpenAI',
error: new NodeApiError(
{
id: '1',
typeVersion: 1,
name: 'OpenAI',
type: 'n8n-nodes-base.openAi',
parameters: {},
position: [100, 200],
},
{
message: `400 - ${JSON.stringify({
error: {
message: 'error message',
type: 'free_ai_credits_request_error',
code: 400,
},
})}`,
error: {
message: 'error message',
type: 'free_ai_credits_request_error',
code: 400,
},
},
{
httpCode: '400',
},
),
},
},
} as unknown as IRun;
expect(userInInstanceRanOutOfFreeAiCredits(runData)).toBe(true);
});
});
function validUrls(idMaker: typeof alphanumericId | typeof email, char = CHAR) {
const firstId = idMaker();
const secondId = idMaker();