Skip to content

Add tests #6483

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 18 commits into
base: next
Choose a base branch
from
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
25 changes: 22 additions & 3 deletions api/parts/mgmt/event_groups.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ const create = (params) => {
'type': 'Boolean'
}
};
if (!params.qstring.args) {
common.returnMessage(params, 400, 'Error: args not found');
return false;
}
params.qstring.args = JSON.parse(params.qstring.args);
const {obj, errors} = common.validateArgs(params.qstring.args, argProps, true);
if (!obj) {
Expand All @@ -59,7 +63,14 @@ const create = (params) => {

/**
* Event Groups CRUD - The function updating which created `Event Groups` data by `_id`
* @param {Object} params -
* @param {Object} params - params object containing the query string and other parameters
* @returns {Boolean}
* This function updates the event groups based on the provided parameters.
* It handles different update scenarios:
* 1. If `args` is provided, it updates the event group with the specified `_id`.
* 2. If `event_order` is provided, it updates the order of the events in the group.
* 3. If `update_status` is provided, it updates the status of the specified event groups.
* 4. If none of these parameters are found, it returns a 400 error indicating that the required arguments are not found.
*/
const update = (params) => {
if (params.qstring.args) {
Expand All @@ -72,7 +83,7 @@ const update = (params) => {
common.returnMessage(params, 200, 'Success');
});
}
if (params.qstring.event_order) {
else if (params.qstring.event_order) {
params.qstring.event_order = JSON.parse(params.qstring.event_order);
var bulkArray = [];
params.qstring.event_order.forEach(function(id, index) {
Expand All @@ -91,7 +102,7 @@ const update = (params) => {
common.returnMessage(params, 200, 'Success');
});
}
if (params.qstring.update_status) {
else if (params.qstring.update_status) {
params.qstring.update_status = JSON.parse(params.qstring.update_status);
params.qstring.status = JSON.parse(params.qstring.status);
var idss = params.qstring.update_status;
Expand Down Expand Up @@ -145,13 +156,21 @@ const update = (params) => {
}
);
}
else {
common.returnMessage(params, 400, 'Error: args not found');
return false;
}
};

/**
* Event Groups CRUD - The function deleting which created `Event Groups` data by `_id`
* @param {Object} params -
*/
const remove = async(params) => {
if (!params.qstring.args) {
common.returnMessage(params, 400, 'Error: args not found');
return false;
}
params.qstring.args = JSON.parse(params.qstring.args);
var idss = params.qstring.args;
common.db.collection(COLLECTION_NAME).remove({_id: { $in: params.qstring.args }}, (error) =>{
Expand Down
136 changes: 136 additions & 0 deletions bin/scripts/adjust_stats.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/**
* Script to check statistics for Adjust data in Countly.
*
* This script checks:
* 1. Number of documents in the adjust collection for the specified app_id
* 2. Number of users in app_users{APP_ID} collection with custom.adjust_id
* 3. Number of adjust_install events in the drill collection
*
* Location:
* Place this script in the `bin/scripts` directory of your Countly installation.
*
* Usage:
* 1. Replace the `APP_ID` variable with the desired app's ID.
* 2. Run the script using Node.js:
* ```
* node /var/countly/bin/scripts/adjust_stats.js
* ```
*/

// Define the APP_ID variable
const APP_ID = '5ab0c3ef92938d0e61cf77f4';

const plugins = require('../../plugins/pluginManager.js');

(async() => {
console.log(`Checking Adjust statistics for APP_ID: ${APP_ID}`);

try {
// Connect to countly database
const db = await plugins.dbConnection("countly");

// Connect to countly_drill database
const drillDb = await plugins.dbConnection("countly_drill");

console.log('Connected to databases successfully.');

// 1. Check how many documents are in adjust collection for this app_id
console.log('\n--- Checking adjust collection ---');

// Define date range for filtering (July 17-22, 2025)
const startDate = new Date('2025-07-17T00:00:00.000Z');
const endDate = new Date('2025-07-22T23:59:59.999Z');
console.log(`Date range filter: ${startDate.toISOString()} to ${endDate.toISOString()}`);

const adjustQuery = {
app_id: APP_ID,
cd: {
$gte: startDate,
$lte: endDate
}
};

const adjustCount = await db.collection('adjust').countDocuments(adjustQuery);
console.log(`Documents in adjust collection for app_id ${APP_ID} (${startDate.toDateString()} - ${endDate.toDateString()}): ${adjustCount}`);

// 1a. Check unique amount of adjust_id values in adjust collection
const uniqueAdjustIds = await db.collection('adjust').distinct('adjust_id', adjustQuery);
console.log(`Unique adjust_id values in adjust collection for app_id ${APP_ID} (${startDate.toDateString()} - ${endDate.toDateString()}): ${uniqueAdjustIds.length}`);

// 1b. Breakdown by event property in adjust collection
console.log('\n--- Event breakdown in adjust collection ---');
const eventBreakdown = await db.collection('adjust').aggregate([
{ $match: adjustQuery },
{ $group: { _id: "$event", count: { $sum: 1 } } },
{ $sort: { count: -1 } }
]).toArray();

console.log('Event breakdown:');
eventBreakdown.forEach(item => {
console.log(` ${item._id}: ${item.count}`);
});

// 2. Check how many users in app_users{APP_ID} collection have custom.adjust_id value
console.log('\n--- Checking app_users collection ---');
const appUsersCollection = 'app_users' + APP_ID;

// Use the same date range but convert to seconds for fac field
const appUsersQuery = {
'custom.adjust_id': { $exists: true },
fac: {
$gte: Math.floor(startDate.getTime() / 1000),
$lte: Math.floor(endDate.getTime() / 1000)
}
};

const usersWithAdjustId = await db.collection(appUsersCollection).countDocuments(appUsersQuery);
console.log(`Users with custom.adjust_id in ${appUsersCollection} (${startDate.toDateString()} - ${endDate.toDateString()}): ${usersWithAdjustId}`);

// 2a. Check unique custom.adjust_id values in app_users collection
const uniqueUserAdjustIds = await db.collection(appUsersCollection).distinct('custom.adjust_id', appUsersQuery);
console.log(`Unique custom.adjust_id values in ${appUsersCollection} (${startDate.toDateString()} - ${endDate.toDateString()}): ${uniqueUserAdjustIds.length}`);

// 3. Check how many adjust_install events are in drill collection
console.log('\n--- Checking drill collection for adjust_install events ---');
const drillCollectionName = 'drill_events';
console.log(`Drill collection name: ${drillCollectionName}`);

// Use the same date range but convert to milliseconds for ts field
const drillQuery = {
"a": APP_ID,
"e": "adjust_install",
ts: {
$gte: startDate.getTime(),
$lte: endDate.getTime()
}
};

const adjustInstallEvents = await drillDb.collection(drillCollectionName).countDocuments(drillQuery);
console.log(`adjust_install events in drill collection (${startDate.toDateString()} - ${endDate.toDateString()}): ${adjustInstallEvents}`);

// 3a. Check unique custom.adjust_id values in drill collection
const uniqueDrillAdjustIds = await drillDb.collection(drillCollectionName).distinct('custom.adjust_id', drillQuery);
console.log(`Unique custom.adjust_id values in drill collection (${startDate.toDateString()} - ${endDate.toDateString()}): ${uniqueDrillAdjustIds.length}`);

// Summary
console.log('\n--- SUMMARY ---');
console.log(`APP_ID: ${APP_ID}`);
console.log(`Date range: ${startDate.toDateString()} - ${endDate.toDateString()}`);
console.log(`Adjust collection documents: ${adjustCount}`);
console.log(`Unique adjust_id values: ${uniqueAdjustIds.length}`);
console.log(`Users with adjust_id: ${usersWithAdjustId}`);
console.log(`Unique custom.adjust_id values in app_users: ${uniqueUserAdjustIds.length}`);
console.log(`adjust_install events in drill collection: ${adjustInstallEvents}`);
console.log(`Unique custom.adjust_id values in drill collection: ${uniqueDrillAdjustIds.length}`);

console.log('\nStatistics check completed.');

}
catch (error) {
console.error('Error during statistics check:', error);
}
finally {
console.log('Terminating the process...');
process.exit(0);
}
})();
36 changes: 36 additions & 0 deletions bin/scripts/generate-api-docs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#!/usr/bin/env node

/**
* This script runs the API documentation generation process:
* 1. Merge all OpenAPI specs into one file
* 2. Generate Swagger UI HTML documentation
*/

const { execFileSync } = require('child_process');
const path = require('path');

console.log('🚀 Starting API documentation generation process...');

// Paths to the scripts
const scriptsDir = __dirname;
const mergeScript = path.join(scriptsDir, 'merge-openapi.js');
const swaggerScript = path.join(scriptsDir, 'generate-swagger-ui.js');

try {
// Step 1: Merge OpenAPI specs
console.log('\n📑 Step 1: Merging OpenAPI specifications...');
execFileSync('node', [mergeScript], { stdio: 'inherit' });

// Step 2: Generate Swagger UI documentation
console.log('\n📙 Step 2: Generating Swagger UI documentation...');
execFileSync('node', [swaggerScript], { stdio: 'inherit' });

console.log('\n✅ API documentation generation completed successfully!');
console.log('📊 Documentation is available in the doc/api directory:');
console.log(' - Swagger UI: doc/api/swagger-ui-api.html');

}
catch (error) {
console.error('\n❌ Error during API documentation generation:', error.message);
process.exit(1);
}
124 changes: 124 additions & 0 deletions bin/scripts/generate-swagger-ui.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
#!/usr/bin/env node

/**
* This script generates HTML documentation using Swagger UI from the merged OpenAPI specification.
*/

const fs = require('fs');
const path = require('path');

// Configuration
const outputDir = path.join(__dirname, '../../doc/api');
const mergedSpecPath = path.join(outputDir, 'openapi-merged.json');
const outputHtmlPath = path.join(outputDir, 'index.html');

// Ensure the merged spec exists
if (!fs.existsSync(mergedSpecPath)) {
console.error(`Merged OpenAPI spec not found at ${mergedSpecPath}`);
console.error('Please run merge-openapi.js first');
process.exit(1);
}

console.log('Generating Swagger UI HTML documentation...');

// Create a simple HTML file with Swagger UI
const swaggerUiHtml = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Countly API Documentation</title>
<link rel="stylesheet" type="text/css" href="https://unpkg.com/swagger-ui-dist@5/swagger-ui.css">
<link rel="icon" type="image/png" href="https://countly.com/images/favicon.png" sizes="32x32" />
<style>
body {
margin: 0;
padding: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}
#swagger-ui {
max-width: 1460px;
margin: 0 auto;
}
.topbar {
background-color: #0166D6 !important;
padding: 10px 0;
text-align: center;
}
.topbar-wrapper img {
content: url('https://countly.com/images/logo.svg');
height: 40px;
}
.swagger-ui .info .title {
color: #0166D6;
}
.swagger-ui .opblock.opblock-get .opblock-summary {
border-color: #0166D6;
}
.swagger-ui .opblock.opblock-get .opblock-summary-method {
background: #0166D6;
}
.swagger-ui .btn.execute {
background-color: #0166D6;
color: #fff;
border-color: #0166D6;
}
.swagger-ui .btn.authorize {
color: #0166D6;
border-color: #0166D6;
}
.swagger-ui .opblock.opblock-post {
background: rgba(1, 102, 214, 0.05);
border-color: #0166D6;
}
</style>
</head>
<body>
<div id="swagger-ui"></div>
<script src="https://unpkg.com/swagger-ui-dist@5/swagger-ui-bundle.js"></script>
<script src="https://unpkg.com/swagger-ui-dist@5/swagger-ui-standalone-preset.js"></script>
<script>
window.onload = function() {
const ui = SwaggerUIBundle({
url: "./openapi-merged.json",
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout",
tagsSorter: 'alpha',
docExpansion: 'list',
defaultModelsExpandDepth: 1,
defaultModelExpandDepth: 1,
filter: true,
supportedSubmitMethods: ['get', 'put', 'post', 'delete', 'options', 'head', 'patch', 'trace'],
validatorUrl: null
});
window.ui = ui;
};
</script>
</body>
</html>
`;

try {
fs.writeFileSync(outputHtmlPath, swaggerUiHtml);

// Also create a copy with the swagger-ui-api.html name for backward compatibility
fs.writeFileSync(path.join(outputDir, 'swagger-ui-api.html'), swaggerUiHtml);

console.log(`Successfully generated Swagger UI documentation at ${outputHtmlPath}`);
console.log(`Also created a copy at ${path.join(outputDir, 'swagger-ui-api.html')} for compatibility`);
}
catch (error) {
console.error('Failed to generate Swagger UI documentation:', error.message);
process.exit(1);
}

console.log('Swagger UI documentation generation completed successfully!');
Loading
Loading