Powered By Blogger

Search Here!

Tuesday, October 8, 2024

Read Excel Content


const XLSX = require("xlsx");
/*
 * Reads content from a specified or latest downloaded Excel file.
 *
 * @param {string|null} [fileName=null] - The name of the Excel file.
*If null, the latest downloaded file will be used.
 * @param {number|null} [rowToCheck=null] - The row number in the
 *Excel content to retrieve (1-based index). If null, all rows will
 *be returned.
 * @returns {Promise<Object|Object[]>} - The content of the
*specified row or all rows if rowToCheck is not provided.
 */
async function getExcelContent(fileName = null, rowToCheck = null) {
    // Define the download directory path
    const downloadDir = CONSTANTS.FILE.FILE_PATH;

    let excelFilePath;

    if (fileName !== null) {
        // Use the provided filename to construct the file path
        excelFilePath = `${downloadDir}/${fileName}`;
        console.log(`Reading content from the specified file:
                        ${fileName}`);
    } else {
        // Get the latest downloaded file name
        const latestDownloadedFileName =
                    await this.getLatestDownloadedFileName();

      // Construct the full path of the latest downloaded Excel file
        excelFilePath = `${downloadDir}/${latestDownloadedFileName}`;
        console.log(
            `Reading content from the latest downloaded file:
                        ${latestDownloadedFileName}`
        );
    }

    // Read the Excel file
    const workbook = XLSX.readFile(excelFilePath);
    const sheetName = workbook.SheetNames[0]; // Get the first sheet
    const sheet = workbook.Sheets[sheetName];
    const data = XLSX.utils.sheet_to_json(sheet);
    // Convert sheet to JSON

    // Print each row of the Excel content in a prettier format
    console.log(`Content of the file ${fileName ||
                                "latest downloaded Excel"}:`);
    data.forEach((row, index) => {
        console.log(`Row ${index + 1}:`);
        for (const [key, value] of Object.entries(row)) {
            console.log(`  ${key}: ${value}`);
        }
        console.log(""); // Add a blank line between rows for
                // readability
    });

    // Return data based on the specified row or all rows
    //if rowToCheck is not provided
    if (rowToCheck !== null) {
        if (rowToCheck < 1 || rowToCheck > data.length) {
           console.warn(`Row number ${rowToCheck} is out of range.`);
           return {}; // Return an empty object if the row number
                // is out of range
        }
        return data[rowToCheck - 1]; // Return the specified row
    }

    return data; // Return all rows
}

Get Pdf Page Counts

 

const pdfParse = require("pdf-parse"); 
* Retrieves the total number of pages in a specified or latest
downloaded PDF file.
 *
 * @param {string|null} [fileName=null] - The name of the PDF file.
*If null, the latest downloaded file will be used.
 * @returns {Promise<number>} - The total number of pages in the
*PDF file.
 */
async function getPdfPageCount(fileName = null) {
    // Define the download directory path
    const downloadDir = CONSTANTS.FILE.FILE_PATH;

    let pdfFilePath;

    if (fileName !== null) {
        // Use the provided filename to construct the file path
        pdfFilePath = `${downloadDir}/${fileName}`;
        console.log(`Getting page count from the specified file:
                        ${fileName}`);
    } else {
        // Get the latest downloaded file name
        const latestDownloadedFileName = await
                        this.getLatestDownloadedFileName();

        // Construct the full path of the latest downloaded PDF file
        pdfFilePath = `${downloadDir}/${latestDownloadedFileName}`;
        console.log(
            `Getting page count from the latest downloaded file:
                            ${latestDownloadedFileName}`
        );
    }

    // Read the PDF file
    const dataBuffer = fs.readFileSync(pdfFilePath);

    // Parse the PDF and extract data
    const data = await pdfParse(dataBuffer);

    // Return the total number of pages
    return data.numpages; // This will return the number of pages
    // starting from 1
}

Get Pdf Text Content Line Based

 

const pdfParse = require("pdf-parse"); 
* Reads the text content from a specified or latest downloaded
PDF file.
 *
 * @param {string|null} [fileName=null] - The name of the PDF file.
If null, the latest downloaded file will be used.
 * @param {number|null} [lineToCheck=null] - The line number in the
PDF content to retrieve (1-based index). If null, all lines will
be returned.
 * @returns {Promise<string|string[]>} - The text content of
the specified line or all lines if lineToCheck is not provided.
 */
async function getPdfTextContentLineBased(fileName = null,
                lineToCheck = null) {
    // Define the download directory path
    const downloadDir = CONSTANTS.FILE.FILE_PATH;

    let pdfFilePath;

    if (fileName !== null) {
        // Use the provided filename to construct the file path
        pdfFilePath = `${downloadDir}/${fileName}`;
        console.log(`Reading content from the specified file:
        ${fileName}`);
    } else {
        // Get the latest downloaded file name
        const latestDownloadedFileName =
                await this.getLatestDownloadedFileName();

        // Construct the full path of the latest downloaded PDF file
        pdfFilePath = `${downloadDir}/${latestDownloadedFileName}`;
        console.log(
            `Reading content from the latest downloaded file:
            ${latestDownloadedFileName}`
        );
    }

    // Read the PDF file
    const dataBuffer = fs.readFileSync(pdfFilePath);

    // Parse the PDF and extract text
    const data = await pdfParse(dataBuffer);

    // Split text into lines
    const lines = data.text.split("\n");

    // Print all lines of the PDF text content
    console.log(`Content of the file ${fileName ||
                    "latest downloaded PDF"}:`);
    console.table(
        lines.map((line, index) => ({ Line: index + 1,
                        Content: line.trim() }))
    );

    // Return text based on the specified line or all lines
if lineToCheck is not provided
    if (lineToCheck !== null) {
        if (lineToCheck < 1 || lineToCheck > lines.length) {
            console.warn(`Line number ${lineToCheck} is out of
                                           range.`);
            return ""; // Return an empty string if
the line number is out of range
        }
        return lines[lineToCheck - 1].trim(); // Return the
specified line
    }

    return lines.map((line) => line.trim()); // Return all lines
}

Tuesday, September 3, 2024

WebdriverIO onPrepare To check Url

 onPrepare: async function () {

        console.log("onPrepare setup started...");
        try {
            // make a request to a reliable server
            await axios.head("https://www.google.com/", { timeout:
            10000 }); // Replace the URL with any reliable server
            console.log("Internet is connected. cheers! 👍");
        } catch (error) {
            console.log("No internet connection or server is
            unreachable 🙄");
            process.exit(1); // Exit the process with an error code
        }
        // url to check accessibility
        const urlsToCheck = [
           "https://www.example.com",
           "https://www.example.com",
           "https://www.example.com",
           "https://www.example.com",
        ];
        for (const urlToCheck of urlsToCheck) {
            try {
                // Send a GET request to the URL
                const response = await axios.get(urlToCheck);
                // Check if the response status is in the
                   success range (e.g., 2xx)
                if (response.status >= 200 && response.status < 300)
                    {
                    console.log(
                        `Url ${urlToCheck} is accessible. Status:
                            ${response.status}` + "👍"
                    );
                } else {
                    console.error(
                        `Url ${urlToCheck} is not accessible.
                            Status: ${response.status}` +
                            "🙄"
                    );
                    await browser.close();
                    process.exit(1); // Exit the process with an
                    error code
                }
            } catch (error) {
                console.error(
                    `Error while checking accessibility of Url
                        ${urlToCheck}:`,
                    error.message
                );
                await browser.close();
                process.exit(1); // Exit the process with an
                error code
            }
        }
        //set maxInstances
        console.log(
            "Set chrome browser maxInstances: " +
                CONSTANT.CONFIG_SETTING.MAXINSTANCES_VALUE +
                "👍😀"
        );
        console.log("onPrepare setup completed..." + "👍👍👍😀");
    },

WebdriverIO Chrome Browser Capabilities For Windows & Linux Environment

wdio.conf.js
// Set the path to the Chromedriver executable based on the
operating system
const isWindows = os.platform() === "win32";
const chromedriverPath = isWindows
    ? "./driver/win/chromedriver.exe" // Path for Chromedriver
on Windows
    : "./driver/linux/chromedriver"; // Path for Chromedriver
on Linux

// Set the path to the Chrome binary based on the operating system
const chromeBinaryPath =
    os.platform() === "win32"
        ? "C:\\Program Files\\Google\\Chrome\\Application
        \\chrome.exe" // Path for Chrome on Windows
        : "/usr/bin/google-chrome"; // Default path for Chrome
on Linux

capabilities: [
        {
            //maxInstances can get overwritten per capability.
So if you have an in-house Selenium
            // grid with only 5 firefox instances available
you can make sure that not more than
            // 5 instances get started at a time.
            browserName: CONSTANT.CONFIG_SETTING.CHROME_BROWSER_NAME,
            acceptInsecureCerts: true,
            "goog:chromeOptions": {
                binary: chromeBinaryPath, // Set the Chrome
                binary path dynamically
                prefs: {
                    credentials_enable_service: false,
                    profile: {
                        password_manager_enabled: false,
                    },
                    w3c: true,
                    download: {
                        default_directory: path.join(process.cwd(),
                        "downloads"),
                        prompt_for_download: false,
                        directory_upgrade: true,
                        "safebrowsing.enabled": false,
                    },
                },
                args: [
                    ...(process.env.HEADLESS === "true"
                        ? ["--headless", "--disable-gpu",
                        "--window-size=1920,1080"]
                        // Configurations for headless mode
                        : []), // No additional args for
                        non-headless mode
                    "--disable-cache",
                    "--no-sandbox",
                    "--disable-dev-shm-usage",
                    "--disable-application-cache",
                    "--disable-offline-load-stale-cache",
                    "--disk-cache-size=0",
                    "--v8-cache-options=off",
                    "--disable-infobars",
                    "--kiosk-printing",
                ].filter(Boolean), // Filter out any empty strings
            },

    ], 

Friday, December 8, 2023

Below is a simplified example of a customized Jira workflow for Product Development and QA (Quality Assurance). This is a basic representation, and you may need to adapt it to match the specific needs and processes of your team or organization.


This is a simple representation, and the actual workflow might be more complex based on your team's specific requirements and processes. Customize the workflow according to your team's needs, and consider integrating it with your version control system and other tools for a seamless development process.

Thursday, December 7, 2023

Calculate Software Automation ROI

Software automation ROI" refers to the Return on Investment (ROI) associated with implementing software automation in a business or organizational context. ROI is a measure used to evaluate the financial benefits of an investment relative to its cost. In the case of software automation, ROI assesses the value gained from automating specific processes or tasks compared to the expenses incurred in implementing and maintaining the automation.

Here are the following calculation parameters: (used google sheets)
 





Considering 2 years(12 months) of ROI projection:

Data Calculation parameters: 

  • Number of test-cases can be automated: (B5 -(B5*B6)/100) 
  • Automation of the test-cases needs: =(($B$7*$B$11)+B9)/B12
  • Time-to-market acceleration: =(B10*B7*B8)/8


Statistics calculation parameters: 


Saved manual testing time (accumulated), hrs = 

  • =$B$10*F21*$B$8*0
  • =H21+($B$10*F22*$B$8) ...

Automation costs (accumulated), hrs =

  • =D21
  • =D22+I21 ...

Autotests run and support cost, hrs= 

  • 0.00
  • =$B$13 ...

Test cases automated = 

  • =IF((E21/$B$11)*B12 >= $B$7, $B$7, (E21/$B$11)*B12)
  • =IF(((E22/$B$11)*$B$12) + $F21 >= $B$7, $B$7, (($E22/$B$11)*$B$12) + F21) ...


Autotests development cost, hrs using standard working hrs/month =

  • =IF($B$14 <= $B$18 * $B$12, $B$14, $B$18*$B$12)
  • =IF(SUM($E$21:E21)+$B$18 >= $B$14, MAX(0, $B$14 - SUM($E$21:E21)), $B$18*$B$12) ...

Automation costs, hrs =

  • =E21+G21
  • =E22+G22 ...

Saved manual testing time, hrs = 

  • =$B$10*F21*$B$8*0
  • =$B$10*F22*$B$8 ...

ROI, hrs = 

  • =H21-I21
  • =H22-I22 ...

Total saved in $ (- ve means in loss) = 

  • =(B45*B17)

Sunday, February 6, 2022

Short Continuous Deployments To Production !

One of my product teams has been successful in deploying to production once every 4 weeks. In the past, our release plan would comprise of an Iterative and incremental development sprint zero, one or three working sprints, one or two alpha or beta sprints, and followed by a hardening sprint. 



We were essentially releasing features to end-users once in every six 8 or more. Our product features are critical to the business. 

Our product team migrated to a shorter release cycle thereby developing and deploying for each sprint and changed to following into 1 month cycle,


Benefits of Small Releases


As the iterative development process is mastered, the door opens for the team to deliver smaller and more frequent releases to the end-users, and that is one of the prime drivers of agile. The ability to release software more frequently has two primary business benefits: increased responsiveness to the customer amidst changing marketing conditions and reduced risk to the enterprise.


  1. Frequent deployments to end-user provide a competitive advantage.
  2. Product requirements could change significantly if deployed to production once every few months. By launching frequently, you could gather data from end-users earlier and apply adjustments accordingly.
  3. Keep your team energized and motivated.
  4. Helps in establishing best practices.
  5. Exposes risks and challenges with design, architecture, and solutions earlier in the process.

Wednesday, December 8, 2021

Upgrade data migration validation !

Purpose:  To make sure  data consistency in upgraded environment.

Thoughts : Dump data base before and after upgrade and check data diff for these 2 data bases.

Available Tools:

  1. dbForge Data Compare for SQL Server
  2. DBDiff 
  3. Pgdatadiff tool 
Environment Setup:

1. dbForge Data Compare for SQL Server

Steps 1: Dump sql file before / after upgrade

docker exec -t vaidio pg_dump --format=c  -U ainvr> dump_`date +%d-%m-%Y"_"%H_%M_%S`.sql

docker exec -t your-db-container pg_dump --format=c -U ainvr > dump_`date +%d-%m-%Y"_"%H_%M_%S`.sql

Steps 2: Create Empty Database

createdb -U postgres -W ainvr;
createdb -U postgres -W ainvr2;

Steps3 : Restore data to created empty database

psql -h localhost -p 5433 -U postgres -f  D:\dump_18-10-2021_13_23_57_before.sql ainvr
psql -h localhost -p 5433 -U postgres -f  D:\dump_18-10-2021_14_33_09_after.sql ainvr2

2. DBDiff Tool                               

DBDiff is an automated database schema and data diff tool.

     It compares two databases, local or remote, and produces a migration file of the differences automatically.

     Command-Line API

Source Code: https://dbdiff.github.io/DBDiff/

Comparison result

Executed Command:

dbdiff postgres://postgres:@localhost:5433/ainvr postgres://postgres:@localhost:5433/ainvr2

Result:

-- DROP TABLE "public"."scene_object_2021_07_26";

-- DROP TABLE "public"."scene_object_2021_07_27";

-- DROP TABLE "public"."scene_object";

-- DROP TABLE "public"."scene_object_2021_07_28";

3. Pgdatadiff Tool

  1. Firstly, compares the row count in both tables.
  2. If the row count is the same, it instructs postgres to create MD5 sums from data.

The MD5 sums are based on the data being cast to varchar. 

If you have data types that don't cast to varchar properly then the behavior probably not reliable. 

Source Code: https://github.com/dmarkey/pgdatadiff

Comparison result

Executed command:

pgdatadiff --firstdb=postgres://postgres:@localhost:5433/ainvr --seconddb=postgres://postgres:@localhost:5433/ainvr2



Future

  • Integrate with Jenkins through ssh set up environment
  • Execute db diff scripts from Jenkins

Recommdation

  •  Pgdatadiff Tool

Firstly it compares the row count in both tables.

If the row count is the same, it instructs postgres to create MD5 sums of "chunks" of the table in both DBs and compares them. This way no data is actually read directly by pgdatadiff, it also means that pgdatadiff is relatively fast but is puts a moderate amount of pressure on the DB as it calculates the MD5 sums of large amounts of data.