Wednesday, March 6, 2019

How to revert a PR with Git ? (reminder)


  • Find the PR you want to revert - Copy the hash

git checkout develop 
git pull
git checkout -b new-branch-name
git revert -m 1 hash # The default editor will open
git push -u origin new-branch-name

  • Create a new PR from the branch 
  • Merge the new PR

Friday, January 25, 2019

How to test a Javascript async function returning a promise with Jest

Overview 

Testing JavaScript asynchronous function with Jest.
Reminders:

  • A JavaScript asynchronous function always return a promise
  • When an JavaScript asynchronous function throw an exception, the function really return a rejected Promise with a value.
  • The Jest test must also be asynchronous
  • As 02/2019 Jest cannot test for custom exception thrown. 


The code

/////////////////////////////////////////////////////////
/// An async function that may throw an exception
export const anAsyncFuncThatThrow = async (fail) => { // Javascript async function always return a Promise
     
    if(fail) 
        throw new Error('an error occured'); // Will return a Promise that is rejected with the error as value 
    
    return new Promise(function(resolve, reject) {
        setTimeout( () => {
        resolve("ok"); // Will return a Promise that is resolved/successful with "ok" as the value
        }, 400);
    });
}

/////////////////////////////////////////////////////////
/// An async function that may resolve or reject the returned promise
export const anAsyncFunc = async (rejectPromise) => { // Javascript async function always return a Promise

    return new Promise(function(resolve, reject) {
        setTimeout( () => {
            if(rejectPromise)
                reject('ko');  // Will return a Promise that is rejected with "ko" as the value
            else
                resolve("ok"); // Will return a Promise that is resolved/successful with "ok" as the value
        }, 400);
    });
}

The tests

  


import { anAsyncFuncThatThrow, anAsyncFunc }  from './p';

describe('anAsyncFuncThatThrow', () => {
 
    it('anAsyncFuncThatThrow succeed', async () => { // <= Do not forget the async keyword for the test
    
        const throwException = false;
        await expect( anAsyncFuncThatThrow(throwException) ).resolves.toEqual('ok'); // expect must be preceded by await
    });
    
    it('anAsyncFuncThatThrow throw', async () => { // <= Do not forget the async keyword for the test
    
        const throwException = true;
        await expect( anAsyncFuncThatThrow(throwException) ).rejects.toThrow(Error); // expect must be preceded by await
    });
    
    it('anAsyncFuncThatThrow throw check error message', async () => { // <= Do not forget the async key work for the test
    
        const throwException = true;
        await expect( anAsyncFuncThatThrow(throwException) ).rejects.toThrow('an error occured'); // expect must be preceded by await
    });
 });

describe('anAsyncFunc', () => {
 
    it('anAsyncFunc succeed', async () => { // <= Do not forget the async keyword for the test
    
        const reject = false;
        await expect( anAsyncFunc(reject) ).resolves.toEqual('ok'); // expect must be preceded by await
    });
    it('anAsyncFunc failed/rejcted', async () => { // <= Do not forget the async keyword for the test
    
        const reject = true;
        await expect( anAsyncFunc(reject) ).rejects.toEqual('ko'); // expect must be preceded by await
    });
});


Sunday, January 13, 2019

Using Azure Container Instance (ACI) to run a console container job using powershell and Azure CLI

Overview

The PowerShell script below uses the Azure CLI, and start the container jrottenberg/ffmpeg and execute the console app  ffmpeg that will extract a thumb nail for an mp4 file.
Both file names are passed as parameters
The 2 files are located on an azure share file and mounted in the container.

The script checks for the existence of each azure resource before creating it.

The script is inspired by the pluralsight class "Azure Container Instances: Getting Started" by Mark Heath.

PowerShell Script Output:
#
# MAIN
#
cls
$fileName  = "vsCode.SyntaxPlanning.Demo.mp4"
$localFile = "C:\DVT\AzureContainerInstance\$fileName"

"Starting thumb nail extraction process Video: $localFile"


# Create Resource group
$resourceGroup = "aciVideoManipulationResourceGroup"
$location      = "eastus"

ExecCode "create resource group $resourceGroup - $location " `
{ az group create -n $resourceGroup -l $location } `
{ (az group exists -n $resourceGroup) }

# Create storage
$storageAccountName = "acivideomanipulation" # $(Get-Random -Minimum 1000 -Maximum 100000)

ExecCode "create storage $storageAccountName" `
{ az storage account create -g $resourceGroup -n $storageAccountName --sku Standard_LRS } `
{ -not ((az storage account check-name  -n $storageAccountName --query "nameAvailable" ) -eq "true") }

# Get storage connection string to upload and download file from the storage
ExecCode "get connection string for $storageAccountName" { 
    $storageConnectionString = az storage account show-connection-string -g $resourceGroup -n $storageAccountName --query "connectionString" -o tsv
    $env:AZURE_STORAGE_CONNECTION_STRING = $storageConnectionString
}

# Create file share in the storage
$shareName = "acivideomanipulationshare"
ExecCode "create file share $shareName" `
{ az storage share create -n $shareName } `
{ ( az storage share exists -n $shareName --query "exists" ) }

# Upload video file to process
ExecCode "upload file:$localFile to share:$shareName" {
    az storage file upload -s $shareName --source "$localFile"
}

# Get the storage key to be passed to the container so the container can mount the file share
ExecCode "get storage key for $storageAccountName" {
    $global:storageKey = $(az storage account keys list -g $resourceGroup -n $storageAccountName --query "[0].value" -o tsv)        
}


# Create the container
$containerGroupName = "transcode"     # Container name
$containerName = "jrottenberg/ffmpeg" # from Docker hub container
$mountedFolder = "/mnt/azfile" # Folder on the container

# Command to be executed by the container after start time.
$commandLine = "ffmpeg -i $mountedFolder/$filename -vf ""thumbnail,scale=640:360"" -frames:v 1 $mountedFolder/thumb.png"

ExecCode "start container" {

    az container create `
        -g $resourceGroup `
        -n $containerGroupName `
        --image $containerName `
        --restart-policy never `
        --azure-file-volume-account-name $storageAccountName `
        --azure-file-volume-account-key "$storageKey" `
        --azure-file-volume-share-name $shareName `
        --azure-file-volume-mount-path "$mountedFolder" `
        --command-line $commandLine
}

ExecCode "check container start status" {

    $status = ToBool(az container show -g $resourceGroup -n $containerGroupName --query "provisioningState" -o tsv)
    Write-Host "Container start status:$status"
}

ExecCode "check container console output/logs" {
    az container logs -g $resourceGroup -n $containerGroupName
}

ExecCode "check for thumb nail output file" {
    
    az storage file list -s $shareName -o table # Check the azure storage file

    $fileFound = (az storage file exists -s $shareName -p "thumb.png" --query "exists")

    # download the created file thumb.png
    $downloadThumbnailPath = ".\thumb.png" 
    az storage file download -s $shareName -p "thumb.png" --dest $downloadThumbnailPath
    Start-Process $downloadThumbnailPath
}

ExecCode "delete container $containerGroupName" {
    az container delete -g $resourceGroup -n $containerGroupName -y
}


ExecCode "delete Resource Group $resourceGroup" {
    # az group delete -n $resourceGroup -y
}

Utility

function ToBool([string] $val) {
    if($val.ToLowerInvariant() -eq "true") {
        return $true
    }
    else {
        return $false
    }
}

function ExecCode($message, $blockOfCode, $blockOfCodeExist) {
    Write-Host ""
    Write-Host "About to $message" -ForegroundColor Cyan
    Try
    {
        $exist = ""
        if($blockOfCodeExist -ne $null) {
            $exist = ToBool ( &$blockOfCodeExist )
        }
        if(!$exist) {
            &$blockOfCode
        }
        else {
            Write-Host "Already exists"
        }        
    }
    Catch
    {
        $ErrorMessage = $_.Exception.Message
        $FailedItem = $_.Exception.ItemName
        Write-Error "Failed:$message, $ErrorMessage, $FailedItem"
        Break
    }
    Write-Host "$message - Done"
}


Friday, January 11, 2019

Repository pattern versus Service layer

What is the difference between the repository pattern and the service layer concept ?

Repository

A Repository is a facade for persistence that implement CRUD access to data/object.

Martin Fowler's Definition.


Service

A service: A class that contains business logic that does not belong to the object model.
A class that implements a set of available operations and coordinates the application's response in each operation.

My guess is that a service could use a repository.

Martin Fowler's Definition.

ASP.NET MVC Web Api / ASP.NET Core Api

In an ASP.NET Core Api, implementing a REST Api, we would find the following layers
  • Controllers
    • Services
      • Repository Implementation
      • EMailNotification Service
      • Other Services
See source code reference  madskristensen Miniblog.Core

Wednesday, December 26, 2018

Quick Moq Reminder


Links



Code Sample


  

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

/// 
/// https://daedtech.com/mock-of-and-mock-get-in-moq/
/// https://www.developerhandbook.com/unit-testing/writing-unit-tests-with-nunit-and-moq/
/// 
namespace MoqPractice
{
    public interface IPerson
    {
        string Name { get; set; }
        int Id { get; set; }
        int ComputeNumber();
    }
    public class Person : IPerson
    {
        public string Name { get; set;}
        public int Id { get; set;}
        public Person(string name)
        {
            this.Name = name;
        }

        public int ComputeNumber()
        {
            return this.Id * 2 + 1; 
        }
    }

    [TestClass]
    public class Person_UnitTests
    {
        [TestMethod]
        public void MockAPropertyFromAnInterface()
        {
            var expectedName = "fred";
            var personMock = new Moq.Mock();
            personMock.SetupGet(m => m.Name).Returns(expectedName);
            Assert.AreEqual(expectedName, personMock.Object.Name);
            personMock.Verify(m => m.Name, Moq.Times.AtLeast(1));
            personMock.Verify(m => m.Name, Moq.Times.AtMost(1));
        }

        [TestMethod]
        public void MockAMethodFromAnInterface()
        {
            var expectedIntValue = 5;
            var personMock = new Moq.Mock();
            personMock.Setup(m => m.ComputeNumber()).Returns(expectedIntValue);
            Assert.AreEqual(expectedIntValue, personMock.Object.ComputeNumber());
            personMock.Verify(m => m.ComputeNumber(), Moq.Times.AtLeast(1));
            personMock.Verify(m => m.ComputeNumber(), Moq.Times.AtMost(1));
        }

        [TestMethod]
        public void MockAPropertyFromAnInterface_Stubbing()
        {
            var expectedName = "fred";
            var personMock = Moq.Mock.Of();
            personMock.Name = expectedName;
            Assert.AreEqual(expectedName, personMock.Name);
        }

        [TestMethod]
        public void MockAProperty_WhichChangeOverTime()
        {
            var personMock = new Moq.Mock();
            var i = 1;
            personMock.SetupGet(t => t.Id).Returns(() => i).Callback(() => i++);
            Assert.AreEqual(1, personMock.Object.Id);
            Assert.AreEqual(2, personMock.Object.Id);
            Assert.AreEqual(3, personMock.Object.Id);
            personMock.Verify(m => m.Id, Moq.Times.Exactly(3));
        }
    }
}


Saturday, November 10, 2018

Debounce and throttle function calls in JavaScript


Overview


Looking at debouncing and throttling function calls in JavaScript.

My source code on StackBlitz.com.

Because I am using global variables to keep track of the state, the function debounce() and throttle()
do  not support debouncing and throttling multiple function at the same time.
  • Throttling and Debouncing in JavaScript blog post by Jhey Tompkins
    • Which contains slightly more complicated version of throttle() function than mine.
  • A visual demo by nimius.net : Demo.

Html





JavaScript

  


    let _inThrottleIgnoredCount = 0;
    let _inThrottle = false;

    function throttle(func, limit = 100) {

        return function() {

            const args = arguments;
            const context = this;
            
            if (_inThrottle) {

                // Do not allow the call, just count the number of ignored call
                _inThrottleIgnoredCount += 1;
            }
            else {

                _inThrottle = true; // Do not allow any more call
                _inThrottleIgnoredCount = 0;
                func.apply(context, args); // Make the first call               
                // Set timer for the period for which we will not allow calls
                setTimeout(function () {

                    _inThrottle = false; // Allow call again
                    if(_inThrottleIgnoredCount > 0) { 
                      // If at least one call came during the period for 
                      // which we were not supposed to accept call, then
                      // let's execute the function one last time
                      _inThrottleIgnoredCount = 0;
                      func.apply(context, args); // Call one last time
                    }
                }, limit);
            }
        }
    }
    
    let _inDebounce = null;

    function debounce(func, delay = 100)  {

        return function() {

            const context = this;
            const args = arguments;
            if(_inDebounce !== null) {

                clearTimeout(_inDebounce); // Cancel pending call
                console.log(`Cancel call`);
            }            
            _inDebounce = setTimeout(() => { 

                _inDebounce = null;
                func.apply(context, args);
            }, delay);
        }
    }

    function doSomething() {
        console.log('doSomething');
    }