RadView Software How-to Building a Performance Testing Framework Development frameworks have been around for years, and have served as a catalyst for a more efficient development process. Next comes the question of how to improve the efficiency of performance testing? In this document will show how to build a testing framework that improves the overall cost-effectiveness of performance testing with WebLOAD.
April 2007
1
Table of Contents Overview ..................................................................................................................... 3 The Need For A Framework................................................................................. 3 Load Testing Framework Architecture ............................................................ 5 Framework Based Testing.................................................................................... 7 The Complete Sample ........................................................................................... 9 Using WebLOAD To Build Your Testing Framework ................................... 9 Building the System API Proxy Layer .......................................................... 9 Building The API Abstraction Layer ............................................................ 10 How to Deploy the Framework in Your Testing Lab ................................ 11 Determining The Included File Location ................................................... 12 Distributing the Files To The Load Generator Machines .................... 12 Change Management ........................................................................................... 12 Future Enhancements.......................................................................................... 13 Class browsing.................................................................................................... 13 Include files intellisense ................................................................................. 14 Multiple file editing ........................................................................................... 14 Appendix – Using Excel As A Data Source For Testing Parameters .. 14 Appendix – The CODE… ...................................................................................... 15 The Agenda .......................................................................................................... 15 The FrameworkSample-AbsAPI.js file ....................................................... 15 The FrameworkSample-ProxyAPI.js file ................................................... 15 The ExcelParamFunction.js File ................................................................... 16
2
Overview Load testing is a potentially ambiguous term with many definitions. We at RadView define load testing by its goals: To guarantee the performance, scalability and reliability of internet applications. As such, an enterprise choosing our solutions for load testing shall find features that address these needs. By “performance” we refer to testing the response time of a given request while the system is under load. By “scalability” we refer to testing the system in response to growing numbers of requests. Finally, “reliability” is about verifying that the response remains correct even under load. When our support professionals work with development teams at large enterprises , they are often asked how to take load testing to the next step and lower the total cost of ownership (TCO) of the load testing process. This document covers our load testing framework architecture and demonstrates how an enterprise can leverage such a framework to get faster and better results from its load testing team.
The Need For A Framework Development frameworks have been around for years, as a means for standardization and acceleration of the development process. The same reasoning applies to testing frameworks. Yet, in the past, many enterprises questioned its cost effectiveness as they questioned the need for test automation at all. While test automation of functional testing can be substituted by manual testing, load testing is always done with automated tools or not done at all. The question of how to make load testing cost effective is still valid and this document will show how a load testing framework can be a key element in justifying its cost. Load testing architecture divides the system into three parts. First, the client GUI application, usually implemented as a browser application using static HTML or a rich internet application such as Ajax applications.
3
Second, is the internet protocol available to access the system under test, usually HTTP/HTTPS but may also include multimedia protocols such as RTP/RTSP or “Web 2.0” protocols such as SOAP/XML or RSS over HTTP. Third and last is the system under test (SUT) which is the subject of our load testing effort. This leads to an important distinction we have to make between functional testing and load testing. While both the client and the Server are tested together in functional testing, each of these components is tested separately during load testing. Adding the client side load into the equation would skew the results because the client processing depends on the client machine (CPU & Memory) which is not simulated using the virtual client load testing model1. Figure 1 - Load testing architecture System under test
System API
Internet protocols
Client GUI application
System API calls using internet protocols
SUT processing
The system API is a new layer that must be mentioned, which is now easier to describe in the context of the growing adoption of service oriented architecture (SOA). In the SOA world the system API are the set of services offered by different sub systems and consumed by the client application, usually in the form of web services. System APIs are of course not limited to the implementation of SOA web services. Any reasonably stable system has some form of separation between the GUI and the business logic, so the business logic functions can be accessed via a stable System API. Since API’s are considered more stable than the trendy GUI application consuming them, a method of load testing which is not affected by the ever changing GUI application would create significant cost savings. This is where the LOAD testing framework comes into play. It enables repeatedly building new load test agendas without recording a new script, eliminating the additional work that may have been caused by changes to the UI. The Load Testing Framework avoids dependence on the UI by directly calling the pre-defined system APIs, like any other callable object within your JavaScript code. The agenda accesses an external resource to 1
A lot has been said on the need for client side load testing with regard to the growing use of client side code like Ajax technology, but still the argument for separating it from the server load testing is still valid and if we consider all the new mash‐up application created by consuming different services into a “bigger” application, the need for separate service testing becomes even clearer.
4
get the parameters for each of the calls. A detailed explanation of the framework architecture is provided in the next section. We will show how the framework can also be resilient to changes in the APIs themselves, acknowledging that backend systems are also prone to change, albeit less often. A detailed description of how the framework handles such changes is listed below, minimizing the effect on the investment that was made in writing the test code itself.
Load Testing Framework Architecture WebLOAD includes all the required elements for building a custom testing framework and is built using a layered architecture approach. In this section you will read about the different components comprising the framework. Some are provided as part of WebLOAD support for the enterprise, others are developed by the load testing team as an enterprise specific framework, while the rest are testing agendas developed for different load testing cycles. The following diagram presents the different layers of such a framework; a detailed description for each part is provided below. WebLOAD IDE framework
System API
Parameterization support
System under test Database
Parameters support layer
Txt
Txt
WebLOAD agenda layer
API Abstraction layer
Sys API Proxy layer
Sys call C interface
Txt
Sys call B interface
Txt
Test Agenda Database
Sys call A interface
System under test with System API – The system being tested is not itself part of the framework, nor is anything that has to be installed on it. It is included as part of the diagram to show that the framework accesses the listed, pre-defined system API.
5
System API proxy layer – This layer represent a static entry point for each of the system API. This layer is built by the testing team as a onetime effort and serves as a basis for all future load testing of the system and the services provided by that system. Each entry point includes only a place holder for parameters, not the specific parameters for each call. The following shows sample code for a System API proxy file: /***** WLIDE - JavaScript - ID:4 *****/ // WebLoad IDE js file
function CelsiusToFahrenheit(Celsius) { /***** WLIDE - URL : http://www.w3schools.com/webservices/tempconvert.asmx/CelsiusToFahrenheit - ID:2 *****/
wlHttp.Header["Referer"] =
"http://www.w3schools.com/webservices/tempconvert.asmx?op=CelsiusToFahrenheit"
wlHttp.ContentType = "application/x-www-form-urlencoded" wlHttp.FormData["Celsius"] = Celsius wlHttp.Post("http://www.w3schools.com/webservices/tempconvert.asmx/CelsiusTo Fahrenheit") return document.wlXmls[0].documentElement.firstChild.nodeValue } function FahrenheitToCelsius(Fahrenheit) { /***** WLIDE - URL : http://www.w3schools.com/webservices/tempconvert.asmx/FahrenheitToCelsius - ID:3 *****/
wlHttp.Header["Referer"] =
"http://www.w3schools.com/webservices/tempconvert.asmx?op=FahrenheitToCelsius"
wlHttp.ContentType = "application/x-www-form-urlencoded" wlHttp.FormData["Fahrenheit"] = Fahrenheit wlHttp.Post("http://www.w3schools.com/webservices/tempconvert.asmx/Fahrenhe itToCelsius") return document.wlXmls[0].documentElement.firstChild.nodeValue }
API Abstraction layer – This layer serves two purposes. First, it provides objects such as interfaces for the system services and makes them easily accessible from the agenda. The second purpose is to provide an abstraction layer for changes in the system API in case they happen. A more detailed description on how to handle changes in the framework is given in section 0. Advanced users can use this layer to achieve better modularity in their test code by wrapping little static system calls in the same object or by using this object for state management between calls. Since this layer is implemented using JavaScript language, you can take advantage of the object oriented characteristics of the language such as templates and others. The following shows sample code for an API abstraction file: /***** WLIDE - JavaScript - ID:2 *****/
IncludeFile("FrameworkSample-ProxyAPI.js", WLExecuteScript) function TemperatureConvertor() { this.ConvertCelsiusToFahrenheit = function (Celsius) { try { return CelsiusToFahrenheit(Celsius) } catch (e) {
6
}
warningMessage("CelsiusToFahrenheit returned an error")
} this.ConvertFahrenheitToCelsius = function (Fahrenheit) { try { return FahrenheitToCelsius(Fahrenheit) } catch (e) { warningMessage("FahrenheitToCelsius returned an error") } } }
WebLOAD agenda layer – This is the load test agenda written by the load testing team. The agenda contains the test code itself, implementing the test logic and setting the specific parameters for each function call. The following shows sample code for an agenda file: function InitAgenda() { IncludeFile("FrameworkSample-AbsAPI.js", WLExecuteScript); } var MyConvertorServices = new TemperatureConvertor () Far = MyConvertorServices.ConvertCelsiusToFahrenheit(30) Cel = MyConvertorServices.ConvertFahrenheitToCelsius(86) InfoMessage("30 degrees celsius are " + Far + " fahrenheit") InfoMessage("86 degrees fahrenheit are " + Cel + " celsius")
Parameterization support – The parameterization support layer is part of the WebLOAD offering which allows the tester to read parameters from different data sources, including text files, excel files and databases. This layer also allows the tester to write their own plug-ins for accessing parameters during runtime.
Framework Based Testing This section provides a step by step guide for writing an agenda based on an existing framework. I will use a sample web service available on the web which provides temperature conversion services. Throughout this document the sample uses Web Services as the protocol between the client and the server. However, non formal API such as XML over Http or any messaging protocol can be used just the same. We start by writing the agenda. Since we have the framework in place we do not have to start with recording a session. Rather, we can go directly to edit modeusing either JavaScript mode or visual edit mode. Let’s test the ConvertCelsiusToFahrenheit service using parameters taken from a global Excel input file. To do so we include the API abstraction layer file in our agenda which makes the ConvertCelsiusToFahrenheit “known” to WebLOAD and we declare the converter object:
7
function InitAgenda() { }
IncludeFile("FrameworkSample-AbsAPI.js", WLExecuteScript);
var MyConvertorServices = new TemperatureConvertor ()
Now we will call our ConvertCelsiusToFahrenheit service which takes the Celsius argument as an input parameter and returns the result in Fahrenheit. In this sample we are still using the hard coded parameter value (“30”) as input. Later we will replace it with an external parameter taken from an Excel file. Far = MyConvertorServices.ConvertCelsiusToFahrenheit(30) InfoMessage("30 degrees celsius are " + Far + " fahrenheit")
Note that although the ConvertCelsiusToFahrenheit method encapsulates an HTTP call to the server, the structure of the method, the HTTP setting and all other technical issues are hidden from the agenda author. As with any good load test we will want to replace the hard coded parameter (in our example, the Celsius argument) with a parameter taken from an external source. Excel is an excellent source for storing test parameters, since it is tabular, easy to use and provides good connectivity to enterprise data sources2. In the following example we created a JavaScript object which reads the lines from a given Excel file and stores them in memory while providing an integrator function to get the parameter. To simplify the code, no error handling is implemented here3. function ReadExcelParameters(FileFullPath) { var xlApp = new ActiveXObject("Excel.Application"); var xlBook= xlApp.Workbooks.Open(FileFullPath); xlBook.worksheets("Sheet1").activate; var xlSheet = xlBook.activeSheet; xlApp.visible = false; var x=0 ; for (x = 1;x<(xlSheet.UsedRange.Rows.Count+1);x++) { RowColData[x] = xlSheet.cells(x,1).value ; } xlBook.Close(); xlApp.Quit(); }
2
Although you can read parameter from an external data source directly using your customer COM/Java object or using excel external data source connection, using static data stored in excel has several advantages, mainly it provides you with predictable results – meaning you can repeat your test over and over again knowing that the input parameters have not changed and not affected your results. More about Excel as a parameter repository see the appendix. 3 Note that in order for this sample to run Excel has to installed on the load generator machine.
8
The Complete Sample The following section lists the complete code of the sample for the above scenario. This sample is based on the sample web service available at http://www.w3schools.com/webservices/tempconvert.asmx. As you can see the test code writing in the agenda itself is very clean and simple which makes it easy to maintain. This sample is comprised of one agenda file (showed below) which references both the FrameworkSample-AbsAPI.js (which is the abstraction layer file) and ExcelParamFunction.js, a helper file with the Excel parameter extraction object . This sample also assumes you have an Excel file on your c:\RadView\Input drive named TempDegrees.xls with a list of the 10 parameters which are to be converted to Fahrenheit. function InitAgenda() { IncludeFile("FrameworkSample-AbsAPI.js") IncludeFile("ExcelParamFunction.js") RowColData = new Array // To hold the temperature degrees values contained in the Excel file
} function InitClient() { ReadExcelParameters("C:\\RadView\\Input\\TempDegrees.xls") } for (i=1;i
Using WebLOAD To Build Your Testing Framework So far we have talked about the need for the framework and what framework based testing looks like. In this section we will describe how to build the enterprise testing framework using different WebLOAD features.
Building the System API Proxy Layer The first step in this process is to build the system API proxy layer. This could be done with a systematic approach where we build the whole layer at once or with an ad hoc approach where we build the different API calls on demand. We start by listing the different services we want to build, usually from a given list supported by the back end system. We then need a client application consuming these services. The client application can be the actual client application used by the enterprise, if one exists, or a test client application that was used by the service developers for unit testing their service. We use the WebLOAD recording feature on this client application to record each of its services at a time in a separate agenda file. The result will be a recording of an HTTP call for a specific service with specific parameters. The following code shows a sample for such a recorded agenda:
9
/***** WLIDE - URL : http://www.w3schools.com/webservices/tempconvert.asmx?op=CelsiusToFahrenheit - ID:2 *****/
//This is the main test page of our web services wlGlobals.GetFrames = false wlHttp.Header["Referer"] = "http://www.w3schools.com/webservices/tempconvert.asmx" wlHttp.FormData["op"] = "CelsiusToFahrenheit" wlHttp.Get("http://www.w3schools.com/webservices/tempconvert.asmx") /***** WLIDE - Sleep - ID:3 *****/
Sleep(6149) /***** WLIDE - URL : http://www.w3schools.com/webservices/tempconvert.asmx/CelsiusToFahrenheit - ID:4 *****/
//This is the call to one of the web services wlHttp.Header["Referer"] = "http://www.w3schools.com/webservices/tempconvert.asmx?op=CelsiusToFahrenheit"
wlHttp.ContentType = "application/x-www-form-urlencoded" wlHttp.FormData["Celsius"] = "30" //Note the hard coded parameter in the recording wlHttp.Post("http://www.w3schools.com/webservices/tempconvert.asmx/CelsiusTo Fahrenheit")
We now have to turn this specific agenda into a framework agenda. We do this by wrapping the call with a function and extracting all the parameters as arguments to that function. We also need to extract the result from the response, which in our sample is the first element in the XML. Once we are done we should use the SAVE AS option in the file menu to save this file in the include directory (see deployment issues later in this document). The following code shows the recorded agenda converted to a function: function CelsiusToFahrenheit(Celsius) { wlGlobals.GetFrames = false wlHttp.Header["Referer"] =
"http://www.w3schools.com/webservices/tempconvert.asmx?op=CelsiusToFahrenheit"
wlHttp.ContentType = "application/x-www-form-urlencoded" wlHttp.FormData["Celsius"] = Celsius //Note the hard coded parameter replaced with function param wlHttp.Post("http://www.w3schools.com/webservices/tempconvert.asmx/CelsiusTo Fahrenheit") //Extract the results
return document.wlXmls[0].documentElement.firstChild.nodeValue }
We are done! We now have the first service implemented as a system API proxy agenda. We now repeat this process for every service we want to implement.
Building The API Abstraction Layer We move on now to building the second layer, which is the API abstraction layer. WebLOAD is based on open standards of web development and uses JavaScript as its main programming language. As an Object Oriented Programming (OOP) language, JavaScript allows you to define your own objects and make your own variable types.
10
All that’s required to build the API abstraction layer is to declare an object with a method and to implement it in a separate agenda file. We will start by creating the object and defining its methods. Our object does not need parameters during construction, so the creation of the object is just a function with no parameters. The following code shows the API abstraction layer object creation: //=============================This is stored in a FrameworkSample-AbsAPI.js /***API Abstraction layer ***/
IncludeFile("FrameworkSample-ProxyAPI.js", WLExecuteScript) function TemperatureConvertor() { this.ConvertCelsiusToFahrenheit = function (Celsius) { try { return CelsiusToFahrenheit(Celsius) } catch (e) { warningMessage("CelsiusToFahrenheit returned an error") } }
As noted before this is a very simplified sample of the abstraction layer. In its place, you can implement any object oriented design practice, for example storing the account number between calls as a property, reporting errors in a centralized manner etc.
How to Deploy the Framework in Your Testing Lab Our testing framework makes use of WebLOAD’s ability to split the agenda into different files and include them in runtime. It is important to understand the search order WebLOAD uses when looking for a given include file.
11
Determining The Included File Location By default, Included Files should be in the “User Include Files” directory specified in the “File Locations” dialog box. You may redirect the default directory location if necessary by double clicking on the “User Include Files” entry and specifying a new file location from the pop-up “Modify Location” browse box. In general, WebLOAD searches for the included file using the following search precedence: The load engine first looks for the included file in the default “User Include Files” directory. If the file is not there, the file request is handed over to WebLOAD, which searches for the file using the following search path order: If a full path name has been hardcoded into the IncludeFile command, the system searches the specified location. If the file is not found in an explicitly coded directory, the system returns an error code of File Not Found and will not search in any other locations. Note: It is not recommended to hard-code a full path name, since the Agenda will then not be portable between different systems. This is especially important for networks that use both Linux and Windows systems. Assuming there is no hardcoded full path name in the Agenda code, the system looks for the file in the default “User Include Files” directory. If the file is not found, the system looks for the file in the current working directory, the directory from which WebLOAD was originally executed. Finally, if the file is still not found, the system searches for the file sequentially through all of the directories listed in the Tools | Options | File Locations dialog box.
Distributing the Files To The Load Generator Machines WebLOAD technology eliminates the need to copy the agenda or any of the include files to the load generator machine. By placing your framework include files in the user include file directory and specifying them as described in the previous section, WebLOAD automatically copies these files to the target load generator machine.
Change Management Change management is one of the key obstacles to test automation. Much effort was put into software engineering with object oriented design patterns and practices all in an effort to minimize the cost of changes. While changes in the code are somewhat acceptable, derived changes in the test code are less acceptable. In this section we show how the framework deals with minimizing the effect of changes and allows better control of the change process.
12
The first step in the process is to understand where changes happen. The most common change in an internet application are changes in the GUI which typically result from a new design or UI fashion or due to the changing needs of clients. By deploying a WebLOAD testing framework, your testing remains unaffected by these types of changes, owing to the protocol-based load testing architecture employed by WebLOAD. Since this architecture is not based on a user emulation level, the test script does not have to change so long as the services called by the application are not changed. Also, since we deployed the testing framework, all of the system APIs are already available to us with no need to record them. Here again, we see that UI changes do not affect us. The second type of changes are changes in the services themselves. Changes to these services are not common and with more and more enterprises implementing Service Oriented Architecture (SOA), these services will become even more immutable. SOA is not another form of object oriented design. It is an evolution of OOP and the three tier architecture, where one of the key factors for making an implementation a successful one are the immutable interfaces. The services interface must be as well defined and immutable as possible, otherwise external users (outside of the scope of your monolithic application users) will not be able to keep up-to-date with your interface changes. However, acknowledging that services do sometime change, it is in our interest to control the change process as much as possible. When service calls change by the addition or removal of a parameter, the first part that is affected is the transaction API calls layer. A new transaction has to be recorded for the given changed service, which does not require a big effort. The question now is how to handle all the scripts that depended on this API call? The framework helps us by using the JavaScript interface layer to control the change. The object in this layer gets the call from the agenda and passes it to the underlying function API layer. Inside this object we can add a default value for the missing parameter, or cut off the extra parameter passed from the agenda layer. Although the API has changed, we can keep our entire agenda repository running by changing only two files. Obviously, a log call can be added in the JavaScript object to log each agenda that uses the “old interface” in order to help the testing team to gradually migrate the test code without breaking it first.
Future Enhancements This document demonstrated how WebLOAD 8.0 can be used to build a testing framework, improving the process of your performance testing team, thus reducing the overall TCO. In future versions of WebLOAD we are considering a few new features which will improve the productivity of framework based testing even more. Here are some examples of areas under development.
Class browsing As noted in this document the framework makes heavy use of include files. A future version of WebLOAD may include some type of object browser which will make navigation through the different framework classes a much easier task.
13
Include files intellisense As with other development environments, it would be very convenient if once we declare an object or function in our JavaScript library it would also show up in our editor with intellisense support.
Multiple file editing Another useful improvement for WebLOAD IDE would be the capability for multiple file editing, eliminating the need to close and open each file over again. Although this task is relevant mainly during the framework development process, other testing tasks might benefit from it as well.
Appendix – Using Excel As A Data Source For Testing Parameters As noted before, Excel is a great tool for managing the test data for both input parameters and test results. With Excel you can choose between using constant test parameters for predictable regression tests, or refreshing the data whenever it is updated by linking an excel sheet to an external data source. The main benefit of linking to external data is that this data can periodically be used in Microsoft Office Excel without repeatedly copying the data, which is an operation that can be time-consuming. After linking to external data, you can also automatically refresh (or update) your Excel workbooks from the original data source whenever the data source is updated with new information. While this is good for testing with real data from existing systems, it has an adverse effect on the predictability of the results since changes in the input parameters affect the results of the test. Therefore, a good test run will include a combination of static regression tests with some dynamic tests. Another advantage of using Excel as a repository for the parameters is test source code management. The Excel file can be easily saved with the agenda file in any source control system allowing better control for the QA team over the test environment configuration. Most projects would like to freeze their test cases along with their code freeze of every version, allowing them to rollback both if needed. This process is much harder to manage if you are using an external data source directly without storing the data in a separate file.
14
Appendix – The CODE… Below is the code for all files used in this document
The Agenda function InitAgenda() { IncludeFile("FrameworkSample-AbsAPI.js") IncludeFile("ExcelParamFunction.js") RowColData = new Array // To hold the temperature degrees values contained in the Excel file } function InitClient() { ReadExcelParameters("C:\\RadView\\Input\\TempDegrees.xls") } for (i=1;i
The FrameworkSample-AbsAPI.js file IncludeFile("FrameworkSample-ProxyAPI.js", WLExecuteScript); function TemperatureConvertor() { this.ConvertCelsiusToFahrenheit = function (Celsius) { try { return CelsiusToFahrenheit(Celsius); } catch (e) { warningMessage("CelsiusToFahrenheit returned an error"); } } this.ConvertFahrenheitToCelsius = function (Fahrenheit) { try { return FahrenheitToCelsius(Fahrenheit); } catch (e) { warningMessage("FahrenheitToCelsius returned an error"); } } }
The FrameworkSample-ProxyAPI.js file function CelsiusToFahrenheit(Celsius) { /***** WLIDE - URL : http://www.w3schools.com/webservices/tempconvert.asmx/CelsiusToFahrenheit - ID:2 *****/ wlHttp.Header["Referer"] = "http://www.w3schools.com/webservices/tempconvert.asmx?op=CelsiusToFahrenheit" wlHttp.ContentType = "application/x-www-form-urlencoded" wlHttp.FormData["Celsius"] = Celsius wlHttp.Post("http://www.w3schools.com/webservices/tempconvert.asmx/CelsiusToFahrenhei t") return document.wlXmls[0].documentElement.firstChild.nodeValue } function FahrenheitToCelsius(Fahrenheit) { /***** WLIDE - URL : http://www.w3schools.com/webservices/tempconvert.asmx/FahrenheitToCelsius - ID:3 *****/ wlHttp.Header["Referer"] = "http://www.w3schools.com/webservices/tempconvert.asmx?op=FahrenheitToCelsius" wlHttp.ContentType = "application/x-www-form-urlencoded"
15
wlHttp.FormData["Fahrenheit"] = Fahrenheit wlHttp.Post("http://www.w3schools.com/webservices/tempconvert.asmx/FahrenheitToCelsiu s") return document.wlXmls[0].documentElement.firstChild.nodeValue }
The ExcelParamFunction.js File function ReadExcelParameters(FileFullPath) { var xlApp = new ActiveXObject("Excel.Application"); var xlBook= xlApp.Workbooks.Open(FileFullPath); xlBook.worksheets("Sheet1").activate; var xlSheet = xlBook.activeSheet; xlApp.visible = false; var x=0 ; for (x = 1;x<(xlSheet.UsedRange.Rows.Count+1);x++) { RowColData[x] = xlSheet.cells(x,1).value ; } xlBook.Close(); xlApp.Quit();
Contact Information: North America
RadView Software Inc. 111 Deerwood Road, Suite: 200 San Ramon, California 94583 Phone: 925-831-4808 Fax: 925-831-4807 Toll Free: 1-888-RadView
United Kingdom
RadView Software (UK) Phone: +44-207-716-5840
Other Countries
RadView Software Ltd. 14 Hamelacha Street Rosh Haayin 48091, Israel Phone: Fax:
+972-3-915-7060 +972-3-915-7683
RadView corporate website: www.radview.com WebLOAD community website: www.webload.org
16