Share your components here

Free for all.

Share your components here

Postby SmartBear Support » 04 May 2011 12:03

So, you have made a custom loadUI component that you think might be useful to other users? Well, go ahead and post it in this topic and it will be published at loadui.org/Custom-Components.

Below is a template that you can use when posting:




Component name:
Process Runner

Developer:
Ole Lensmar, eviware

Description:
Runs an operating system process. Example component taken from http://www.eviware.com/blog/?p=196.

Source code:
Code: Select all
/**
* Runs a process
*
* @name Process Runner
* @category runners
*/

// the command itself
createProperty('command', String,"")

sample = { message, sampleId ->
   try
   {
      // start a process and wait for it to finish
      def proc = command.value.execute()
      proc.waitFor()                             

      // add result properties
      message["ExitValue"] = proc.exitValue()
      message["Stdout"] = proc.in.text
      message["Errout"] = proc.err.text

      // fail if process failed
      if( proc.exitValue() != 0 )
         failureCounter.increment()
   }
   catch( e )
   {
      // add error properties
      message["ExitValue"] = -1
      message["Errout"] = e.message

      failureCounter.increment()
   }

   return message
}

layout {
    property( property:command, label:"Command", constraints: 'w 200!' )
    action( label:'Run Once', action: { triggerAction('SAMPLE') }, constraints: 'aligny bottom' )
}
SmartBear Support
Administrator
Administrator
 
Posts: 6702
Joined: 16 Feb 2009 10:53

Re: Share your components here

Postby erikralenius » 12 May 2011 06:50

Component name:
JIRA

Developer:
Erik Rålenius

Description:
Creates a JIRA issue for all Web Page Runner failures after a completed test


Source code:
Code: Select all
//
// Copyright (C) 2011  Erik Rålenius (erik@ralenius.se)

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

/**
* Create JIRA issue for Web Page Runner failures.
*
* @name JIRA
* @category output
* @dependency org.codehaus.groovy:groovy-xmlrpc:0.4
*/

import groovy.net.xmlrpc.XMLRPCServerProxy as Proxy
import com.eviware.loadui.util.layout.DelayedFormattedString
import com.eviware.loadui.api.events.ActionEvent
import com.eviware.loadui.api.events.PropertyEvent
import com.eviware.loadui.impl.component.ActivityStrategies

class JiraProxy extends Proxy {
    JiraProxy(url) { super(url) }
    Object invokeMethod(String methodname, args) {
        super.invokeMethod('jira1.'+methodname, args)
    }
}

createProperty('project', String)
createProperty('type', Integer, 1)
createProperty('priority', Long, 4)
createProperty('assignee', String)
createProperty('jiraServer', String)
createProperty('username', String)
password = createProperty('_password', String)
createProperty('maxCapturedFailures', Integer, 100)

status = 'Not ready'
issueDescription = ""
capturedFailures = 0
isConnected = false

capturedFailuresDisplay = new DelayedFormattedString('%d', 200, value {capturedFailures} )
statusDisplay = new DelayedFormattedString('%s', 200, value {status})

addEventListener( ActionEvent ) { event ->
    if (isConnected && event.key == 'START' ) {
        status = 'Capturing'
        setActivityStrategy(ActivityStrategies.BLINKING)
    }
    else if (isConnected && event.key == 'STOP') {
        status = 'Stopped'
        setActivityStrategy(ActivityStrategies.OFF)
    }
    else if (isConnected && event.key == 'COMPLETE') {
        if (capturedFailures > 0) {
            createIssue()
            issueDescription = ""
            setActivityStrategy(ActivityStrategies.OFF)
        } else {
            status = 'No captures'
        }
    }
   else if (event.key == 'RESET') {       
        capturedFailures = 0
        issuesDescription = ""
   }
}

output = { message ->
    if (capturedFailures < maxCapturedFailures.value) {
        if (isConnected && message['Status'] == false) {
            addFailureToIssue(message)
            capturedFailures++
        }
   }
}

onConnect = { outgoing, incoming ->
    if (outgoing.terminalHolder.label == 'Web Page Runner'
        && outgoing.label == 'resultTerminal') {
        isConnected = true
        status = 'Ready'
    }
}

onDisconnect = { outgoing, incoming ->
    isConnected = false
    status = 'Not ready'
}

onRelease = {
   capturedFailuresDisplay.release()
   statusDisplay.release()
}

// Layout
layout {
    property(property: maxCapturedFailures, label: 'Max captured failures', min: 1, max: 100)
    separator(vertical: true)
    box(widget: 'display') {
        node(label: 'Failures captured', fString: capturedFailuresDisplay, constraints: 'wmin 75')
        node(label: 'Status', fString: statusDisplay, constraints: 'wmin 75')
   }
}

compactLayout {
    box(widget:'display') {
        node(label: 'Failures captured', fString: capturedFailuresDisplay, constraints: 'wmin 75')
        node(label: 'Status', fString: statusDisplay, constraints: 'wmin 75')
   }   
}

// Settings
settings(label: 'Issue properties') {
    property(property: project, label: 'Project (required)')
    property(property: assignee, label: 'Assignee')
    box {
        property(property: priority, label:
            'Priority (1: Blocker, 2: Critical, 3: Major, 4: Minor, 5: Trivial)')
    }
}

settings(label: 'Authentication') {
    property(property: jiraServer, label: 'JIRA server')
    property(property: username, label: 'Username')
    property(property: password, widget: 'password', label: 'Pasword')
}

private def addFailureToIssue(message) {
    generatorsProperties = getGeneratorPropertiesAsMessage()
    formatedTimestamp = timestampToFormatedDate(message['TriggerTimestamp'])
    issueDescription += """Request to ${message['ID']} failed at $formatedTimestamp
$generatorsProperties
---

"""
}

private def timestampToFormatedDate(long timestamp) {
    return new Date(timestamp)
}

private def createIssue() {
    // JIRA won't accept null values
    if (assignee.value == null) {
        assignee.value = ""
    }
   
    Map issueData =
    [
        summary: "loadUI: $capturedFailures failures captured while running ${canvas.label}",
        description: issueDescription,
        type: 1,
        assignee: assignee.value,
        project: project.value,
        priority: priority.value
    ]
   
    String jiraURL = "${jiraServer.value}/rpc/xmlrpc"
   
    try {
        jira = new JiraProxy(jiraURL)
        loginToken = jira.login(username.value, password.value)
        issue = jira.createIssue(loginToken, issueData)
        status = 'Issue created'
    }
    catch (exception) {
         log.error(exception.message, exception)
        status = 'Creation failed'     
    }
}

private def getGeneratorPropertiesAsMessage() {
    message = ""
    for (component in canvas.components) {
        if (component.category == 'generators') {
            message = message + "\n" + "Generator: " + component.label + "\n"
            for (property in component.properties) {
                if (isAllowed(property.key)) {
                    message = message + property.key.capitalize() + ": " + property.value + "\n"
                }
            }
        }
    }
    return message
}

private def isAllowed(key) {
    return key[0] != '_' && key != 'ModelItem.description';
}
erikralenius
User
 
Posts: 8
Joined: 24 Mar 2011 21:46

Custom HTTP Runner

Postby thzinc » 30 Aug 2011 17:35

Component Name
Custom HTTP Runner

Developer
Daniel James, Casting Networks, Inc.

Description
Derivative of Web Runner, Custom HTTP Runner allows you to execute an HTTP request using any method desired. (e.g., GET, HEAD, POST, PUT, any other arbitrary verb) The Custom HTTP Runner also allows you to specify a pre-encoded HTTP entity body, which is especially useful for POST or PUT requests.

Source Code
Code: Select all
// Custom HTTP Runner, Copyright 2011 Casting Networks, Inc.
//
// Derivative work of Web Runner, Copyright 2011 eviware software ab
//
// Licensed under the EUPL, Version 1.1 or - as soon they will be approved by the European Commission - subsequent
// versions of the EUPL (the "Licence");
// You may not use this work except in compliance with the Licence.
// You may obtain a copy of the Licence at:
//
// http://ec.europa.eu/idabc/eupl5
//
// Unless required by applicable law or agreed to in writing, software distributed under the Licence is
// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the Licence for the specific language governing permissions and limitations
// under the Licence.
//

/**
* Sends an HTTP request
*
* @id com.castingnetworksinc.CustomHTTPRunner
* @help http://www.loadui.org/Runners/web-page-runner-component.html
* @name Custom HTTP Runner
* @category runners
* @dependency org.apache.httpcomponents:httpcore:4.1
* @dependency org.apache.httpcomponents:httpclient:4.1.1
*/

import org.apache.http.*
import org.apache.http.client.*
import org.apache.http.auth.*
import org.apache.http.conn.params.*
import org.apache.http.conn.scheme.*
import org.apache.http.client.methods.*
import org.apache.http.conn.ClientConnectionManager
import org.apache.http.entity.StringEntity
import org.apache.http.util.EntityUtils
import org.apache.http.impl.client.DefaultHttpClient
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager
import com.eviware.loadui.api.events.ActionEvent
import com.eviware.loadui.api.events.PropertyEvent
import com.eviware.loadui.api.model.CanvasItem
import com.eviware.loadui.impl.component.categories.RunnerBase.SampleCancelledException
import com.eviware.loadui.impl.component.ActivityStrategies
import com.eviware.loadui.util.layout.DelayedFormattedString
import com.eviware.loadui.util.ReleasableUtils

import java.util.concurrent.TimeUnit

import org.apache.http.conn.scheme.Scheme
import org.apache.http.conn.ssl.SSLSocketFactory
import java.net.URI
import javax.net.ssl.SSLContext
import javax.net.ssl.KeyManager
import javax.net.ssl.TrustManager
import javax.net.ssl.X509TrustManager
import java.security.cert.X509Certificate
import java.security.cert.CertificateException
import java.security.SecureRandom
import java.util.HashMap
import java.util.Map
import java.util.concurrent.TimeUnit

// Create a custom HTTP request based off of the Apache HTTP Client base class
class HttpCustom extends HttpEntityEnclosingRequestBase {
   def _method
  HttpCustom(method, uri) {
     super.setURI(URI.create(uri))
     _method = method
  }
 
  String getMethod() { _method }
}

scheduleAtFixedRate( { updateLed() }, 500, 500, TimeUnit.MILLISECONDS )

createOutput( 'statisticsOutput', 'Statistics', 'Connect to a Statistics component to feed it with the displayed values.' )

//SSL support, trust all certificates and hostnames.
class NaiveTrustManager implements X509TrustManager {
   void checkClientTrusted ( X509Certificate[] cert, String authType ) throws CertificateException {}
   void checkServerTrusted ( X509Certificate[] cert, String authType ) throws CertificateException {}
   X509Certificate[] getAcceptedIssuers () { null }
}
def sslContext = SSLContext.getInstance("SSL")
TrustManager[] tms = [ new NaiveTrustManager() ]
sslContext.init( new KeyManager[0], tms, new SecureRandom() )
def sslSocketFactory = new SSLSocketFactory( sslContext )
sslSocketFactory.setHostnameVerifier( SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER )

def sr = new SchemeRegistry()
sr.register( new Scheme( "http", 80, PlainSocketFactory.socketFactory ) )
sr.register( new Scheme( "https", 443, sslSocketFactory ) )

def cm = new ThreadSafeClientConnManager( sr )
cm.maxTotal = 50000
cm.defaultMaxPerRoute = 50000


//Properties
createProperty( 'url', String ) { ->
   validateUrl()
}

// Default method to GET
createProperty( 'method', String, 'GET' )
createProperty( 'entityBody', String )
createProperty( 'outputBody', Boolean, false )

createProperty( 'readResponse', Boolean, false )
createProperty( 'errorCodeList', String )

createProperty( 'proxyHost', String )
createProperty( 'proxyPort', Long )
createProperty( 'proxyUsername', String )
proxyPassword = createProperty( '_proxyPassword', String )
authUsername = createProperty( '_authUsername', String )
authPassword = createProperty( '_authPassword', String )

http = new DefaultHttpClient( cm )

inlineUrlAuthUsername = null
inlineUrlAuthPassword = null
         
def runningSamples = ([] as Set).asSynchronized()
runAction = null

def dummyUrl = "http://GoSpamYourself.com"

validateUrl = { 
   if( url.value && !( url.value.toLowerCase().startsWith( "http://" ) || url.value.toLowerCase().startsWith( "https://" ) ) ) {
      url.value = "http://" + url.value
   }
   
   if( url.value =~ /https?:\/\/(www\.)?(eviware\.com|(soapui|loadui)\.org)(\/.*)?/ ) url.value = dummyUrl
   
   // extract possible username and password from username:password@domain syntax
   matcher = url.value?.replace( "http://", "" ) =~ /([^:]+):([^@]+)@(.+)/
   if ( matcher ) {
      inlineUrlAuthUsername = matcher[0][1]
      inlineUrlAuthPassword = matcher[0][2]
   } else {
      inlineUrlAuthUsername = inlineUrlAuthPassword = null
   }
   updateAuth()
   
   setInvalid( !url.value || url.value == dummyUrl )
   runAction?.enabled = !isInvalid()
}

updateLed = {
   setActivityStrategy( runAction?.enabled ? ( currentlyRunning > 0 ? ActivityStrategies.BLINKING : ActivityStrategies.ON ) : ActivityStrategies.OFF )
}

updateProxy = {
   if( proxyHost.value?.trim() && proxyPort.value ) {
      HttpHost hcProxyHost = new HttpHost( proxyHost.value, (int)proxyPort.value, "http" )
      http.params.setParameter( ConnRoutePNames.DEFAULT_PROXY, hcProxyHost )
      
      if( proxyUsername.value?.trim() && proxyPassword.value ) {
         http.credentialsProvider.setCredentials(
            new AuthScope( proxyHost.value, (int)proxyPort.value ),
            new UsernamePasswordCredentials( proxyUsername.value, proxyPassword.value )
         )
      } else {
         http.credentialsProvider.clear()
      }
   } else {
      http.params.setParameter( ConnRoutePNames.DEFAULT_PROXY, null )
   }
}

updateAuth = {
   def username = null
   def password = null
   if( inlineUrlAuthUsername && inlineUrlAuthPassword ) {
      username = inlineUrlAuthUsername
      password = inlineUrlAuthPassword
   } else if( authUsername.value?.trim() && authPassword.value?.trim() ) {
      username = authUsername.value
      password = authPassword.value
   }
   
   if( username && password ) {
      http.credentialsProvider.setCredentials(
         new AuthScope( AuthScope.ANY ),
         new UsernamePasswordCredentials( username, password )
      )
   }
}

validateUrl()
updateProxy()

requestResetValue = 0
sampleResetValue = 0
discardResetValue = 0
failedResetValue = 0

displayRequests = new DelayedFormattedString( '%d', 500, value { requestCounter.get() - requestResetValue } )
displayRunning = new DelayedFormattedString( '%d', 500, value { currentlyRunning } )
displayTotal = new DelayedFormattedString( '%d', 500,  value { sampleCounter.get() - sampleResetValue } )
displayQueue = new DelayedFormattedString( '%d', 500, value { queueSize } )
displayDiscarded = new DelayedFormattedString( '%d', 500,  value { discardCounter.get() - discardResetValue } )
displayFailed = new DelayedFormattedString( '%d', 500,  value { failureCounter.get() - failedResetValue } )

sample = { message, sampleId ->
   def uri = message['url'] ?: url.value
   def method = message['method'] ?: method.value
   def entityBody = message['entityBody'] ?: entityBody.value ?: ""
   
   if( uri ) {
      def httpRequest = new HttpCustom( method, uri )
      httpRequest.setEntity(new StringEntity(entityBody, "application/x-www-form-urlencoded", "utf-8"))
      message['ID'] = method + " " + uri + "?" + entityBody
      
      runningSamples.add( httpRequest )
      try {
         def response = http.execute( httpRequest )
         message['Status'] = true
         message['URI'] = uri
         message['HttpStatus'] = response.statusLine.statusCode
         
         if( errorCodeList.value ) {
            def assertionCodes = errorCodeList.value.split(',')
            
            for( code in assertionCodes ) {
               if( code.trim() == response.statusLine.statusCode.toString() ) {
                  failedRequestCounter.increment()
                  failureCounter.increment()
                  break
               }
            }
         }
         
         if( response.entity != null )   {
            int contentLength = response.entity.contentLength
            message['Bytes'] = contentLength
            
            if( outputBody.value )
               message['Response'] = EntityUtils.toString( response.entity )
            
            if( contentLength < 0 ) {
               if( outputBody.value )
                  message['Bytes'] = message['Response'].length()
               else
                  message['Bytes'] = EntityUtils.toString( response.entity ).length()
            }
            
            response.entity.consumeContent()
            
            if( !runningSamples.remove( httpRequest ) ) {
               throw new SampleCancelledException()
            }
            
            return message
         }
      } catch( e ) {
         if( e instanceof SampleCancelledException )
            throw e
         
         if( e instanceof IOException )
            log.warn( "IOException in {}: {}", label, e.message )
         else
            log.error( "Exception in $label:", e )
         
         httpRequest.abort()
         
         if ( !runningSamples.remove( httpRequest ) ) {
            throw new SampleCancelledException()
         }
         
         message['Status'] = false
         message['Exception'] = e.toString()
         failedRequestCounter.increment()
         failureCounter.increment()
         
         return message
      }
   } else {
      throw new SampleCancelledException()
   }

}

onCancel = {
   def numberOfRunning = 0
   synchronized( runningSamples ) {
      def methods = runningSamples.toArray()
      numberOfRunning = methods.size()
      runningSamples.clear()
      methods.each { if( !it.aborted ) it.abort() }
   }
   
   return numberOfRunning
}

onRelease = {
   ReleasableUtils.releaseAll( displayRunning, displayTotal, displayQueue, displayDiscarded, displayFailed, displayRequests )
}

onAction( "RESET" ) {
   requestResetValue = 0
   sampleResetValue = 0
   discardResetValue = 0
   failedResetValue = 0
}

addEventListener( PropertyEvent ) { event ->
   if ( event.event == PropertyEvent.Event.VALUE ) {
      if( event.property in [ proxyHost, proxyPort, proxyUsername, proxyPassword, authUsername, authPassword ] ) {
         http.credentialsProvider.clear()
         updateProxy()
         updateAuth()
      }
   }
}

//Layout
layout {
   box( layout:'wrap 2, ins 0' ) {
      property( property:method, label:'HTTP Method', constraints: 'w 300!, spanx 2')
      property( property:url, label:'URL', constraints: 'w 300!, spanx 2', style: '-fx-font-size: 17pt' )
      property( property:entityBody, label:'HTTP Entity Body', constraints: 'w 300!, spanx 2')
      runAction = action( label:'Run Once', action: { triggerAction( 'SAMPLE' ) } )
      action( label:'Abort Running Pages', action: { triggerAction( 'CANCEL' ) } )
   }
   separator(vertical:true)
   box( layout:'wrap, ins 0' ){
      box( widget:'display', layout:'wrap 3, align right' ) {
         node( label:'Requests', fString:displayRequests, constraints:'w 50!' )
         node( label:'Running', fString:displayRunning, constraints:'w 50!' )
         node( label:'Completed', fString:displayTotal, constraints:'w 60!' )
         node( label:'Queued', fString:displayQueue, constraints:'w 50!' )
         node( label:'Discarded', fString:displayDiscarded, constraints:'w 50!' )
         node( label:'Failed', fString:displayFailed, constraints:'w 60!' )
      }
      action( label:'Reset', action: {
         requestResetValue = requestCounter.get()
         sampleResetValue = sampleCounter.get()
         discardResetValue = discardCounter.get()
         failedResetValue = failureCounter.get()
         triggerAction('CANCEL')
      }, constraints:'align right' )
   }
}

//Compact Layout
compactLayout {
   box( widget:'display', layout:'wrap 3, align right' ) {
      node( label:'Requests', fString:displayRequests, constraints:'w 50!' )
      node( label:'Running', fString:displayRunning, constraints:'w 50!' )
      node( label:'Completed', fString:displayTotal, constraints:'w 60!' )
      node( label:'Queued', fString:displayQueue, constraints:'w 50!' )
      node( label:'Discarded', fString:displayDiscarded, constraints:'w 50!' )
      node( label:'Failed', fString:displayFailed, constraints:'w 60!' )
   }
}

settings( label: "Basic" ) {
   property( property: outputBody, label: 'Output Response Body' )
   //property( property: propagateSession, label: 'Propagate Session' )
   property( property: readResponse, label: 'Read Response' )
   property( property: concurrentSamples, label: 'Max Concurrent Requests' )
   property( property: maxQueueSize, label: 'Max Queue' )
   property( property: errorCodeList, label: 'Error Codes that Count as Failures', constraints:'w 200!')
   property( property: countDiscarded, label: 'Count Discarded Requests as Failed' )
}

settings( label: "Authentication" ) {
   property( property: authUsername, label: 'Username' )
   property( property: authPassword, widget: 'password', label: 'Password' )
}

settings( label: "Proxy" ) {
   property( property: proxyHost, label: 'Proxy Host' )
   property( property: proxyPort, label: 'Proxy Port' )
   property( property: proxyUsername, label: 'Proxy Username' )
   property( property: proxyPassword, widget: 'password', label: 'Proxy Password' )
}

scheduleAtFixedRate( {
   def message = newMessage()
   Integer.with {
      message["Requests"] = parseInt( displayRequests.currentValue )
      message["Running"] = parseInt( displayRunning.currentValue )
      message["Discarded"] = parseInt( displayDiscarded.currentValue )
      message["Failed"] = parseInt( displayFailed.currentValue )
      message["Queued"] = parseInt( displayQueue.currentValue )
      message["Completed"] = parseInt( displayTotal.currentValue )
   }
   send( statisticsOutput, message )
}, 1, 1, TimeUnit.SECONDS )

def statisticsSignature = [
   "Requests" : Integer.class,
   "Running" : Integer.class,
   "Discarded" : Integer.class,
   "Failed" : Integer.class,
   "Queued" : Integer.class,
   "Completed" : Integer.class
]

setSignature( statisticsOutput, statisticsSignature )
thzinc
User
 
Posts: 6
Joined: 18 Aug 2011 17:33

Re: Custom HTTP Runner

Postby SmartBear Support » 13 Sep 2011 08:52

thzinc wrote:Component Name
Custom HTTP Runner

Developer
Daniel James, Casting Networks, Inc.

[...]

Looking really good Daniel! :)

In case you haven't already noticed, your component have been published in the custom components gallery.

Henrik
loadUI developer
SmartBear Support
Administrator
Administrator
 
Posts: 6702
Joined: 16 Feb 2009 10:53

Re: Share your components here

Postby tunen2fate » 28 Sep 2011 15:43

I love this comp. However when I am testing this it seems that I do not have a place to connect to. Why is that am i missing a step someplace? I added a screenshot of what am saying. i hope this is the right place for this if not I am sorry in advance.
Attachments
2011-09-28_0941LOAD.png
SCREENSHOT
2011-09-28_0941LOAD.png (29.01 KiB) Viewed 11176 times
tunen2fate
User
 
Posts: 7
Joined: 27 Sep 2011 22:44

Re: Share your components here

Postby erikralenius » 01 Dec 2011 17:14

Hi!

I have now updated the JIRA plugin to fix the problems with the missing connection point and also the missing smack depencency.

You can download the new version from my personal site: http://erik.r.yverling.se/creations/plugin/jira or from the custom component gallery: http://www.loadui.org/Custom-Components

Happy load testing!
Erik R. Yverling (formally Rålenius)
erikralenius
User
 
Posts: 8
Joined: 24 Mar 2011 21:46

Re: Share your components here

Postby Elvorin » 09 Mar 2012 00:12

Component name:
Rate Multiplier

Developer:
Abhishek Dasgupta

Description:
Multiplies the rate of attached Generators (rate based) for easy load setting increase/decrease while keeping the load distribution ratio intact.

Source code:
Code: Select all

/**
* Multiplies the rate of attached Generators (rate based) for easy load increase/decrease
* while keeping the load distribution ratio intact.
*
* @name Rate Multiplier
* @nonBlocking false
*/

import com.eviware.loadui.util.layout.DelayedFormattedString

import java.lang.Math


// inputs and outputs
createOutput('multiplierOutput', 'Multiplier', 'Multiply current rate with')

// properties
createProperty('multiplicationFactor', Long, 1) { newRate, oldRate ->
   displayFactor.setArgs(multiplicationFactor.value)
   
   if (oldRate == null) {
      oldRate = storedRate
   }
   
   adjustRate(oldRate, newRate)
}

displayFactor = new DelayedFormattedString('x %d', 200, multiplicationFactor.value)
storedRate = multiplicationFactor.value
calculatedNewRate = 1;
calculatedNewUnit = 'Sec'

onRelease = {
   displayFactor.release()
}

def adjustRate(oldRate, newRate) {
   def connectedComponent
   for (c in multiplierOutput.connections) {
      connectedComponent = c.inputTerminal.terminalHolder
      if (connectedComponent.category == 'generators') {
         //Supports only the generators with 'rate' property
         //Assumption is it will also have a 'unit' property with Sec, Min, Hour as possible values
         if (connectedComponent.getProperty("rate") != null) {
            def generatorRate = connectedComponent.getProperty("rate").value
            def generatorUnit = connectedComponent.getProperty("unit").getStringValue()
            calculateRateAndUnit(oldRate, newRate, generatorRate, generatorUnit)
            
            connectedComponent.getProperty("rate").value = calculatedNewRate
            connectedComponent.getProperty("unit").setValue(calculatedNewUnit)
         }
      }
   }
}

def calculateRateAndUnit(oldRate, newRate, generatorRate, generatorUnit) {
   //Convert rate to hour for easier calculation
   def multiplyBy = 1;
   if (generatorUnit == 'Sec') {
      multiplyBy = (60 * 60)
   } else if (generatorUnit == 'Min') {
      multiplyBy = 60
   }
   
   calculatedNewUnit = 'Hour'
   calculatedNewRate = (generatorRate * multiplyBy)
   
   //Round rate
   if (newRate > oldRate) {
      calculatedNewRate = Math.ceil((calculatedNewRate * newRate) / oldRate)
   } else {
      calculatedNewRate = Math.floor((calculatedNewRate * newRate) / oldRate)
   }
   
   if (calculatedNewRate == 0) {
      calculatedNewRate = 1
   }
   
   //Normalize
   if ((calculatedNewRate % 60) == 0) {
      calculatedNewUnit = 'Min'
      calculatedNewRate = (calculatedNewRate / 60)
      
      if ((calculatedNewRate % 60) == 0) {
         calculatedNewUnit = 'Sec'
         calculatedNewRate = (calculatedNewRate / 60)
      }
   }
}

// main layout
layout {
   property(property:multiplicationFactor, label:'Multiplier', min:1)
   separator(vertical:true)
   box(widget:'display') {
      node(label:'Multiplication Factor', fString:displayFactor, constraints:'wmin 75')
   }
}

// compact layout
compactLayout {
   box(widget:'display') {
      node(label:'Multiplication Factor', fString:displayFactor)
   }
}

// basic settings tab
settings(label:'Basic') {
   property( property:multiplicationFactor, label:'Multiplication Factor')
}



Note:
[*] This currently works only with rate based generators, i.e. Fixed, Random and Variance.
[*] If multiplier is changed very rapidly and randomly, error might get thrown from the random generators due to a previously reported bug (viewtopic.php?f=12&t=12859)
[*] As rate is a whole number, changing multiplier value back-n-forth may not bring the initial rate setting back due to rounding up/down operation done during rate value calculation.

Any suggestion to improve the component is most welcome.
Attachments
Example.png
Example.png (97.93 KiB) Viewed 8304 times
RateMultiplier.zip
(3.72 KiB) Downloaded 958 times
Elvorin
User
 
Posts: 44
Joined: 15 Feb 2012 19:29

Re: Custom HTTP Runner

Postby njcoutinho » 13 Apr 2012 05:34

SmartBear Support wrote:
thzinc wrote:Component Name
Custom HTTP Runner

Developer
Daniel James, Casting Networks, Inc.

[...]

Looking really good Daniel! :)

In case you haven't already noticed, your component have been published in the custom components gallery.

Henrik
loadUI developer



Hi Daniel ,

Where can i find the documentation of your product
njcoutinho
User
 
Posts: 3
Joined: 03 Mar 2012 05:46

Re: Share your components here

Postby lomewbartho » 27 Apr 2012 12:29

Derivative of Web Runner, Custom HTTP Runner allows you to execute an HTTP request using any method desired. (e.g., GET, HEAD, POST, PUT, any other arbitrary verb) The Custom HTTP Runner also allows you to specify a pre-encoded HTTP entity body, which is especially useful for POST or PUT requests.Derivative of Web Runner, Custom HTTP Runner allows you to execute an HTTP request using any method desired. (e.g., GET, HEAD, POST, PUT, any other arbitrary verb) The Custom HTTP Runner also allows you to specify a pre-encoded HTTP entity body, which is especially useful for POST or PUT requests.Derivative of Web Runner, Custom HTTP Runner allows you to execute an HTTP request using any method desired. (e.g., GET, HEAD, POST, PUT, any other arbitrary verb) The Custom HTTP Runner also allows you to specify a pre-encoded HTTP entity body, which is especially useful for POST or PUT requests.
Lomew bartho
lomewbartho
User
 
Posts: 1
Joined: 27 Apr 2012 12:21

Re: Share your components here

Postby inkless » 29 May 2012 15:00

Component name:
HTML Runner

Description:
Fetches a webpage (including images) and runs JavaScript.

Source code:
Code: Select all
/**
* Fetches a web page.
*
* @id com.eviware.HtmlRunner
* @name HTML Runner
* @category runners
* @dependency org.apache.httpcomponents:httpcore:4.1
* @dependency org.apache.httpcomponents:httpclient:4.1.1
* @dependency net.sourceforge.htmlunit:htmlunit:2.9
*/

import org.apache.http.*
import org.apache.http.client.*
import org.apache.http.auth.*
import org.apache.http.conn.params.*
import org.apache.http.conn.scheme.*
import org.apache.http.impl.client.BasicCredentialsProvider
import com.eviware.loadui.api.events.PropertyEvent
import com.eviware.loadui.impl.component.categories.RunnerBase.SampleCancelledException

import org.apache.http.conn.scheme.Scheme
import org.apache.http.conn.ssl.SSLSocketFactory
import javax.net.ssl.SSLContext
import javax.net.ssl.KeyManager
import javax.net.ssl.TrustManager
import javax.net.ssl.X509TrustManager
import java.security.cert.X509Certificate
import java.security.cert.CertificateException
import java.security.SecureRandom
import java.util.HashMap
import java.util.concurrent.TimeUnit

import com.gargoylesoftware.htmlunit.WebClient
import com.gargoylesoftware.htmlunit.WebRequestSettings

//SSL support, trust all certificates and hostnames.
class NaiveTrustManager implements X509TrustManager {
   void checkClientTrusted ( X509Certificate[] cert, String authType ) throws CertificateException {}
   void checkServerTrusted ( X509Certificate[] cert, String authType ) throws CertificateException {}
   X509Certificate[] getAcceptedIssuers () { null }
}
def sslContext = SSLContext.getInstance( 'SSL' )
TrustManager[] tms = [ new NaiveTrustManager() ]
sslContext.init( new KeyManager[0], tms, new SecureRandom() )
def sslSocketFactory = new SSLSocketFactory( sslContext )
sslSocketFactory.hostnameVerifier = SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER

def sr = new SchemeRegistry()
sr.register( new Scheme( "http", PlainSocketFactory.socketFactory, 80 ) )
sr.register( new Scheme( "https", sslSocketFactory, 443 ) )

//Properties
createProperty( 'url', String ) { ->
   validateUrl()
}
createProperty( 'outputBody', Boolean, false )
createProperty( 'downloadResources', Boolean, true )
createProperty( 'runJavaScript', Boolean, true )
createProperty( 'errorCodeList', String )

authUsername = createProperty( '_authUsername', String )
authPassword = createProperty( '_authPassword', String )

inlineUrlAuthUsername = null
inlineUrlAuthPassword = null
credentialsProvider = new BasicCredentialsProvider()
         
def runningSamples = ( [] as Set ).asSynchronized()
runAction = null

def dummyUrl = "http://GoSpamYourself.com"

validateUrl = {
   if( url.value && !( url.value.toLowerCase().startsWith( "http://" ) || url.value.toLowerCase().startsWith( "https://" ) ) ) {
      url.value = "http://" + url.value
   }
   
   if( url.value =~ /https?:\/\/(www\.)?(eviware\.com|(soapui|loadui)\.org)(\/.*)?/ ) url.value = dummyUrl
   
   // extract possible username and password from username:password@domain syntax
   matcher = url.value?.replace( "http://", "" ) =~ /([^:]+):([^@]+)@(.+)/
   if ( matcher ) {
      inlineUrlAuthUsername = matcher[0][1]
      inlineUrlAuthPassword = matcher[0][2]
   } else {
      inlineUrlAuthUsername = inlineUrlAuthPassword = null
   }
   updateAuth()
   
   try {
      new URI( url.value )
      setInvalid( !url.value || url.value == dummyUrl )
   } catch( e ) {
      setInvalid( true )
   }
   
   runAction?.enabled = !isInvalid()
}

updateAuth = {
   def username = null
   def password = null
   if( inlineUrlAuthUsername && inlineUrlAuthPassword ) {
      username = inlineUrlAuthUsername
      password = inlineUrlAuthPassword
   } else if( authUsername.value?.trim() && authPassword.value?.trim() ) {
      username = authUsername.value
      password = authPassword.value
   }
   
   if( username && password ) {
      credentialsProvider.setCredentials(
         new AuthScope( AuthScope.ANY ),
         new UsernamePasswordCredentials( username, password )
      )
   }
}

validateUrl()

requestResetValue = 0
sampleResetValue = 0
discardResetValue = 0
failedResetValue = 0


acceptTypes = new HashMap<String, String>()
acceptTypes.put("html", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
acceptTypes.put("img", "image/png,image/*;q=0.8,*/*;q=0.5")
acceptTypes.put("script", "*/*")
acceptTypes.put("style", "text/css,*/*;q=0.1")

def downloadCssAndImages( page ) {
   def bytesDownloaded = 0
   def xPathExpression = "//*[name() = 'img' or name() = 'link' and @type = 'text/css']"
   def resultList = page.getByXPath(xPathExpression)
   resultList.each {
      try {
         println( "next is $it" )

         def path = it.getAttribute( 'src' ).equals( '' ) ? it.getAttribute( 'href' ) : it.getAttribute( 'src' )
         if ( path != null && !path.equals( '' ) ) {

            def url = page.getFullyQualifiedUrl(path)
            def wrs = new WebRequestSettings(url)
            wrs.setAdditionalHeader( 'Referer', page.webResponse.requestSettings.url.toString() )

            client.addRequestHeader( 'Accept', acceptTypes[ it.tagName.toLowerCase() ] )
            bytesDownloaded += client.getPage( wrs ).webResponse.contentAsString.length()
            println( "downloading $wrs" )
         }
      } catch ( e ) { println "!!! $e" }
   }

   client.removeRequestHeader( 'Accept' )
   return bytesDownloaded
}

sample = { message, sampleId ->

   def uri = message['url'] ?: url.value
   if( uri ) {
      message['ID'] = uri
      
      client = new WebClient()
      client.setJavaScriptEnabled( runJavaScript.value )
      runningSamples.add( client )
      try {
         //client.setCredentialsProvider( credentialsProvider )
         def page = client.getPage( uri )
         
         def bytesDownloaded = 0
         if( downloadResources.value )
            bytesDownloaded = downloadCssAndImages( page )
      
         //def response = http.execute( get )
         message['Status'] = true
         message['URI'] = uri
         def statusCode = page.webResponse.statusCode
         message['HttpStatus'] = statusCode
         
         if( errorCodeList.value ) {
            def assertionCodes = errorCodeList.value.split(',')*.trim()
            if( assertionCodes.contains( statusCode.toString() ) )
            {
               failedRequestCounter.increment()
               failureCounter.increment()
            }
         }
         
         if( true /* response.entity != null */ )   {
            message['Bytes'] = page.webResponse.contentAsString.length() + bytesDownloaded
            
            if( outputBody.value )
               message['Response'] = page.webResponse.contentAsString()
            
            if( !runningSamples.remove( client ) ) {
               throw new SampleCancelledException()
            }
            
            return message
         }
      } catch( e ) {
         if( e instanceof SampleCancelledException )
            throw e
         
         if( e instanceof IOException )
            log.warn( "IOException in {}: {}", label, e.message )
         else
            log.error( "Exception in $label:", e )
         
         if ( !runningSamples.remove( client ) ) {
            throw new SampleCancelledException()
         }
         
         message['Status'] = false
         failedRequestCounter.increment()
         failureCounter.increment()
         
         return message
      }
   } else {
      throw new SampleCancelledException()
   }

}

/*
onCancel = {
   def numberOfRunning = 0
   synchronized( runningSamples ) {
      def methods = runningSamples.toArray()
      numberOfRunning = methods.size()
      runningSamples.clear()
      methods.each { if( !it.aborted ) it.abort() }
   }
   
   return numberOfRunning
}*/

onAction( 'RESET' ) {
   requestResetValue = 0
   sampleResetValue = 0
   discardResetValue = 0
   failedResetValue = 0
}

addEventListener( PropertyEvent ) { event ->
   if ( event.event == PropertyEvent.Event.VALUE ) {
      if( event.property in [ authUsername, authPassword ] ) {
         credentialsProvider.clear()
         updateAuth()
      }
   }
}

//Layout
layout {
   box( layout:'wrap 2, ins 0' ) {
      property( property:url, label:'Web Page Address', constraints: 'w 270!, spanx 2' )
      
      separator()
      
      property( property:runJavaScript, label:'Enable JavaScript', constraints: 'w 110!, spanx 1' )
      property( property:downloadResources, label:'Download images and CSS', constraints: 'w 150!, spanx 1' )
      
      runAction = action( label:'Run Once', action: { triggerAction( 'SAMPLE' ) } )
      action( label:'Abort Running Pages', action: { triggerAction( 'CANCEL' ) } )
   }
   separator(vertical:true)
   box( layout:'wrap, ins 0' ){
      box( widget:'display', layout:'wrap 3, align right' ) {
         node( label:'Requests', content: { requestCounter.get() - requestResetValue }, constraints:'w 50!' )
         node( label:'Running', content: { currentlyRunning }, constraints:'w 50!' )
         node( label:'Completed', content: { sampleCounter.get() - sampleResetValue }, constraints:'w 60!' )
         node( label:'Queued', content: { queueSize }, constraints:'w 50!' )
         node( label:'Discarded', content: { discardCounter.get() - discardResetValue }, constraints:'w 50!' )
         node( label:'Failed', content: { failureCounter.get() - failedResetValue }, constraints:'w 60!' )
      }
      action( label:'Reset', action: {
         requestResetValue = requestCounter.get()
         sampleResetValue = sampleCounter.get()
         discardResetValue = discardCounter.get()
         failedResetValue = failureCounter.get()
         triggerAction( 'CANCEL' )
      }, constraints:'align right' )
   }
}

//Compact Layout
compactLayout {
   box( widget:'display', layout:'wrap 3, align right' ) {
      node( label:'Requests', content: { requestCounter.get() - requestResetValue }, constraints:'w 50!' )
      node( label:'Running', content: { currentlyRunning }, constraints:'w 50!' )
      node( label:'Completed', content: { sampleCounter.get() - sampleResetValue }, constraints:'w 60!' )
      node( label:'Queued', content: { queueSize }, constraints:'w 50!' )
      node( label:'Discarded', content: { discardCounter.get() - discardResetValue }, constraints:'w 50!' )
      node( label:'Failed', content: { failureCounter.get() - failedResetValue }, constraints:'w 60!' )
   }
}

settings( label: 'Basic' ) {
   property( property: outputBody, label: 'Output Response Body' )
   property( property: concurrentSamples, label: 'Max Concurrent Requests' )
   property( property: maxQueueSize, label: 'Max Queue' )
   property( property: errorCodeList, label: 'Error Codes that Count as Failures', constraints:'w 200!')
   property( property: countDiscarded, label: 'Count Discarded Requests as Failed' )
}

settings( label: 'Authentication' ) {
   property( property: authUsername, label: 'Username' )
   property( property: authPassword, widget: 'password', label: 'Password' )
}
inkless
User
 
Posts: 1
Joined: 29 May 2012 14:55

Re: Share your components here

Postby SmartBear Support » 05 Jun 2012 10:04

Component name:
Geb Runner

Description:
Runs Geb scripts. Geb is a browser automation solution for Groovy that can be used for functional/web/acceptance testing. This component has been published here: http://loadui.org/Custom-Components/

Source code:
Code: Select all
/**
* Runs a Geb (http://www.gebish.org/) Script
*
* @name Geb Runner
* @category runners
* @id com.eviware.GebRunner
* @dependency net.sourceforge.htmlunit:htmlunit:2.9
* @dependency org.codehaus.geb:geb-core:latest.release
* @dependency org.seleniumhq.selenium:selenium-htmlunit-driver:2.4.0
*/

import com.eviware.loadui.impl.component.categories.RunnerBase.SampleCancelledException

import java.util.HashSet
import java.util.Collections

import groovy.lang.GroovyShell
import groovy.lang.Binding


//Properties
createProperty( 'scriptFile', File, null, false )
createProperty( 'cacheScriptContent', Boolean, true, false )
createProperty( 'setBinding', Boolean, true )
scriptContent = createProperty( '_scriptContent', String ) {
   parseScript()
}

runningSamples = Collections.synchronizedSet( new HashSet() )

requestResetValue = 0
sampleResetValue = 0
discardResetValue = 0
failedResetValue = 0
runButton = null

parseScript = {
   if( !scriptContent.value )
   {
      runButton?.enabled = false
      return
   }

   try {
      //script = shell.parse( imports + scriptContent.value )
      log.info( scriptContent.value )
      runButton?.enabled = true
   } catch( e ) {
      log.error( e.message, e )
      runButton?.enabled = false
   }
}

//We'll only ever read the file on the controller, and send out the script content as a String to the agents.
if( controller ) {
   lastModified = null
   updateScript = {
      if( scriptFile.value && scriptFile.value.exists() ) {
         if( lastModified != scriptFile.value.lastModified() ) {
            scriptContent.value = scriptFile.value.text
            lastModified = scriptFile.value.lastModified()
            parseScript()
         }
      } else {
         lastModified = null
         scriptContent.value = null
      }
   }
   updateScript()
   
   onReplace( scriptFile, updateScript )
   onReplace( cacheScriptContent, updateScript )
}


sample = { message, sampleId ->
   try {
      runningSamples.add( Thread.currentThread() )
      if( controller && !cacheScriptContent.value )
         updateScript()
      
      def result = evaluate( scriptContent.value )

      message['Status'] = true
      if( result instanceof Map ) {
          message.putAll( result )
      } else {
          message['Result'] = String.valueOf( result )
      }
   } catch( Throwable e ) {
      if( e instanceof InterruptedException )
          throw new SampleCancelledException()
      message['Status'] = false
      message['Result'] = e.toString()
      //failedRequestCounter.increment()
      failureCounter.increment()
   } finally {
      runningSamples.remove( Thread.currentThread() )
   }

   return message
}

onCancel = {
   synchronized( runningSamples ) {
      def threads = runningSamples.toArray()
      runningSamples.clear()
      threads.each { it.interrupt() }
      return threads.length
   }
}

onAction( "RESET" ) {
   if( controller ) updateScript()
   requestResetValue = 0
   sampleResetValue = 0
   discardResetValue = 0
   failedResetValue = 0
}

//Layout
layout {
   box( layout: 'wrap 2, ins 0' ) {
      property( property: scriptFile, label: 'Geb Script File', constraints: 'w 300!, spanx 2', style: '-fx-font-size: 17pt' )
      property( property: cacheScriptContent, label: 'Cache script content', constraints: 'growx, spanx 2' )
      separator()
      runButton = action( label: 'Run Once', action: { triggerAction('SAMPLE') }, enabled: ( scriptFile.value && scriptFile.value.exists() ) )
      action( label: 'Abort Running Scripts', action: { triggerAction('CANCEL') } )
   }
   separator( vertical: true )
   box( layout: 'wrap, ins 0' ){
      box( widget: 'display', layout: 'wrap 3, align right', column: '[50|50|60]' ) {
          node( label: 'Requests', content: { requestCounter.get() - requestResetValue } )
          node( label: 'Running', content: { currentlyRunning } )
          node( label: 'Completed', content: { sampleCounter.get() - sampleResetValue } )
          node( label: 'Queued', content: { queueSize } )
          node( label: 'Discarded', content: { discardCounter.get() - discardResetValue } )
          node( label: 'Failed', content: { failureCounter.get() - failedResetValue } )
      }
      action( label: 'Reset', action: {
          requestResetValue = requestCounter.get()
          sampleResetValue = sampleCounter.get()
          discardResetValue = discardCounter.get()
          failedResetValue = failureCounter.get()
          triggerAction('CANCEL')
      }, constraints:'align right' )
   }
}

compactLayout {
   box( widget: 'display', layout: 'wrap 3, align right', column: '[50|50|60]' ) {
      node( label: 'Requests', content: { requestCounter.get() - requestResetValue } )
      node( label: 'Running', content: { currentlyRunning } )
      node( label: 'Completed', content: { sampleCounter.get() - sampleResetValue } )
      node( label: 'Queued', content: { queueSize } )
      node( label: 'Discarded', content: { discardCounter.get() - discardResetValue } )
      node( label: 'Failed', content: { failureCounter.get() - failedResetValue } )
   }
}

settings( label: "Basic" ) {
   property( property: setBinding, label: 'Make trigger message parameters available to the script' )
}
SmartBear Support
Administrator
Administrator
 
Posts: 6702
Joined: 16 Feb 2009 10:53

Re: Custom HTTP Runner

Postby thzinc » 31 Mar 2013 05:48

njcoutinho wrote:
SmartBear Support wrote:
thzinc wrote:Component Name
Custom HTTP Runner

Developer
Daniel James, Casting Networks, Inc.

[...]

Looking really good Daniel! :)

In case you haven't already noticed, your component have been published in the custom components gallery.

Henrik
loadUI developer


Hi Daniel ,

Where can i find the documentation of your product


I just replied to your post at viewtopic.php?f=10&t=13056&p=42078&sid=b0c689d8b822911fd4da3a8862037e81#p42078
thzinc
User
 
Posts: 6
Joined: 18 Aug 2011 17:33


Return to LoadUI