All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.blitz.curl.AbstractTest Maven / Gradle / Ivy

The newest version!
package io.blitz.curl;

import com.google.gson.internal.LazilyParsedNumber;
import io.blitz.curl.exception.AuthenticationException;
import io.blitz.curl.exception.BlitzException;
import io.blitz.curl.exception.ValidationException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;

/**
 * Abstract class that templates the core tests execution
 * @author ghermeto
 */
public abstract class AbstractTest 
    extends TestEntity implements IObservable {
    
    
    /**
     * Transient property used to connect the client when necessary. 
     * Not meant to be serialized.
     */
    private transient String username;
    
    /**
     * Transient property used to connect the client when necessary. 
     * Not meant to be serialized.
     */
    private transient String apiKey;
    
    /**
     * Transient property used to connect the client when necessary. 
     * Not meant to be serialized.
     */
    private transient String host;
    
    /**
     * Transient property used to connect the client when necessary. 
     * Not meant to be serialized.
     */
    private transient Integer port;
    
    /**
     * Connects with the server and handle the request/response.
     * Not meant to be serialized.
     */
    private transient Client client;
    
    /**
     * Transient property to be used during a test execution. 
     * Not meant to be serialized.
     */
    private transient String jobId;
    
    /**
     * Listener to be notified when the Client send a response.
     * Will not be serialized into the json.
     */
    private transient Collection listeners;
    
    /**
     * Adds a listener to the test which will fire when the test receives a 
     * status response from the client. The execute method does not invoke the
     * listeners. When on error, will throw an exception and on success will
     * update jobId.
     * @param listner IListener to be notified
     * @see io.blitz.curl.IObservable
     */
    public void addListener(Listener listner) {
        if (listeners == null) {
           listeners = new ArrayList(); 
        }
        listeners.add(listner);
    }

    /**
     * Removes the given listener from the list.
     * @param listner IListener to be removed from the list
     * @see io.blitz.curl.IObservable
     */
    public void removeListener(Listener listner) {
        listeners.remove(listner);
    }
    
    /**
     * This method verifies the test requirements and throws a 
     * ValidationException when necessary.
     * @throws io.blitz.curl.exception.ValidationException
     * @see io.blitz.curl.Sprint#checkRequirements() 
     * @see io.blitz.curl.Rush#checkRequirements() 
     */
    public abstract void checkRequirements() throws ValidationException;
    
    /**
     * Executes the test. During its execution it will receive updates from the 
     * Client and will notify all attached listeners.
     */
    public void execute() {
        //specific for each subclass
        checkRequirements();
        //handle the client creation
        createClientInstance();
        //handle client authentication
        if(!client.isAuthenticated()) {
            Map response = client.login();
            if (response.containsKey("error")) {
                String error = (String) response.get("error");
                String reason = (String) response.get("reason");
                throw new AuthenticationException(error, reason);
            }
        }
        //after authentication, we send this job to the server (excluding transient)
        Map response = client.execute(this);
        
        if(response.containsKey("error")) {
            String error = (String) response.get("error");
            String reason = (String) response.get("reason");
            throw new BlitzException(error, reason);
        }
        
        jobId = (String) response.get("job_id");
        checkStatus();
    }
    
    /**
     * Notify all listneres about an success response from blitz. It calls  
     * onStatus on all listeners. If a listener returns false, 
     * it will automatically call abort after notifying all.
     * @param result the result object from the JSON response
     * @return if the execution will be aborted
     */
    protected boolean notifyStatus(Map result) {
        boolean progress = true;
        if(listeners != null) {
            Result success = createSuccessResult(result);
            for(Listener listener : listeners) {
                 progress = progress && listener.onStatus(success);
            }
            if(!progress) {
                abort();
            }
        }
        return progress;
    }
    
    /**
     * Notify all listneres that the test finished successfully.
     * @param result the result object from the JSON response 
     */
    protected void notifyComplete(Map result) {
        if(listeners != null) {
            Result success = createSuccessResult(result);
            for(Listener listener : listeners) {
                 listener.onComplete(success);
            }
        }
    }
    
    /**
     * Should return a Result object populated with the 
     * successful response from the server.
     * @param result the deserialized result from the JSON response
     * @see io.blitz.curl.Sprint#createSuccessResult(java.util.Map) 
     * @see io.blitz.curl.Rush#createSuccessResult(java.util.Map) 
     */
    protected abstract Result createSuccessResult(Map result);

    /**
     * Verifies if the client instance was created and tries to create a new 
     * instance if needed.
     */
    protected void createClientInstance() {
        if (client == null) {
            if (username == null || apiKey == null) {
                throw new AuthenticationException("No credentials");
            }
            else if(host != null && port != null) {
                client = new Client(username, apiKey, host, port);
            }
            else {
                client = new Client(username, apiKey);
            }
        }
    }
    
    /**
     * Checks the current job status and notify the listeners about errors and 
     * sucessful responses from the server.
     */
    public void checkStatus() {
        try {
            do {
                Thread.sleep(2000);

                Map job = client.getJobStatus(jobId);
                Map result = getResult(job);
                String status = (String) job.get("status");

                if(job == null) {
                    throw new BlitzException("client", "No response.");
                }
                //if no result was issued yet (nothing to notify)
                else if("queued".equalsIgnoreCase(status) || 
                    ("running".equalsIgnoreCase(status) && result == null)) {
                    
                    continue;
                }
                //if the server retuned an error
                else if(job.containsKey("error")) {
                    String error = (String) job.get("error");
                    String reason = (String) job.get("reason");
                    throw new BlitzException(error, reason);
                }
                //if the result was an error
                else if(result != null && result.containsKey("error")) {
                    String error = (String) result.get("error");
                    String reason = (String) result.get("reason");
                    throw new BlitzException(error, reason);
                }
                else if("completed".equalsIgnoreCase(status)) {
                    // notify the listeners that the test was successful
                    notifyComplete(result);
                    break;
                }
                //notify the listeners that a successful status was acquired
                if(!notifyStatus(result)) {
                    break;
                }
                
            }while(true);
            
        } catch (InterruptedException ex) {
            throw new BlitzException("client", ex.getLocalizedMessage());
        }
    }
    
    /**
     * Verifies if the job has a result map and returns it.
     * @param job map response from the job status
     * @return the job result map or null
     */
    private Map getResult(Map job) {
        if(job != null && job.get("result") != null) {
            Object obj = job.get("result");
            if(Map.class.isAssignableFrom(obj.getClass())) {
                return (Map) obj;
            }
        }
        return null;
    }
    
    /**
     * Stores the user credentials to be used by the Client. The user
     * credentials are available at http://blitz.io on the Settings page or it can
     * be found by typing --api-key on the blitz play bar.
     * @param username blitz.io username
     * @param apiKey blitz.io authentication api key
     */
    protected void setCredentials(String username, String apiKey) {
        this.username = username;
        this.apiKey = apiKey;
    }

    /**
     * Stores the user credentials to be used by the Client. The user
     * credentials are available at http://blitz.io on the Settings page or it can
     * be found by typing --api-key on the blitz play bar.
     * @param username blitz.io username
     * @param apiKey blitz.io authentication api key
     * @param host the host to connect
     * @param port the port to connect
     */
    protected void setCredentials(String username, String apiKey, String host, Integer port) {
        this.username = username;
        this.apiKey = apiKey;
        this.host = host;
        this.port = port;
    }
    
    /**
     * Aborts the current job. Sending a abort request doesn't guarantee that 
     * the job will stop immediately.
     * @return true if the server accepts the request
     */
    protected boolean abort() {
        Map job = client.abort(jobId);
        return job != null && job.containsKey("ok");
    }

    /**
     * Convert com.google.gson.internal.LazilyParsedNumber to Integer
     * @param number LazilyParsedNumber
     * @return integer
     */
    protected Integer parseInt(Object number) {
        if (number.getClass().isAssignableFrom(LazilyParsedNumber.class)) {
            return ((LazilyParsedNumber)number).intValue();
        }
        return (Integer) number;
    }
    
    /**
     * convert com.google.gson.internal.LazilyParsedNumber to Double
     * @param number LazilyParsedNumber
     * @return double
     */
    protected Double parseDouble(Object number) {
        if (number.getClass().isAssignableFrom(LazilyParsedNumber.class)) {
            return ((LazilyParsedNumber)number).doubleValue();
        }
        return (Double) number;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy