Chris Lacy's Software Engineering Blog

Friday Dec 23, 2011

Linux VPN Restart Python Script

Usage: ./vpnRestart <interface id> <vpn id>
For example: ./vpnRestart eth0 myVpn
Tested on Fedora and Ubuntu

#!/usr/bin/env python


import logging
import sys, getopt
import time
import gobject, dbus
from dbus.mainloop.glib import DBusGMainLoop



class DbusHelper:


    basePackage = None
    systemBus = None


    def __init__(self, basePackage):

        self.basePackage = basePackage
        self.systemBus = dbus.SystemBus()


    def createProxy(self, path):

        return self.systemBus.get_object(self.basePackage, path)


    def createInterface(self, proxy, interfacePackage):

        return dbus.Interface(proxy, dbus_interface=interfacePackage)


    def createIface(self, proxyPath, interfacePackage):

        return self.createInterface(self.createProxy(proxyPath), interfacePackage)


    def addReceiver(self, handler, interface, signalName):

        self.systemBus.add_signal_receiver(handler,
	    dbus_interface=interface,
	    signal_name=signalName)



class DbusPropertiesHelper:


    interfacePath = None
    propertiesI = None


    def __init__(self, proxyPath, dbusHelper, interfacePath):

        self.interfacePath = interfacePath
        self.propertiesI = dbusHelper.createIface(proxyPath, 'org.freedesktop.DBus.Properties')


    def get(self, prop):

        return self.propertiesI.Get(self.interfacePath, prop)



class NetworkManagerHelper:


    FAILED = 6
    DISCONNECTED = 7


    interfaceQuery = None
    vpnQuery = None


    dbusHelper = None
    networkManagerI = None
    settingsI = None


    def __init__(self, interfaceQuery, vpnQuery):

        self.interfaceQuery = interfaceQuery
        self.vpnQuery = vpnQuery

        DBusGMainLoop(set_as_default=True)
        self.dbusHelper = DbusHelper('org.freedesktop.NetworkManager')
        self.networkManagerI = self.dbusHelper.createIface('/org/freedesktop/NetworkManager', 'org.freedesktop.NetworkManager')
        self.settingsI = self.dbusHelper.createIface('/org/freedesktop/NetworkManager/Settings', 'org.freedesktop.NetworkManager.Settings')


    def findConnection(self, query):

        connection = None

        for c in self.getConnections():

            ci = self.dbusHelper.createIface(c, 'org.freedesktop.NetworkManager.Settings.Connection')
            settings = ci.GetSettings()
            
            if settings['connection']['id'].find(query) != -1:
                connection = c
                break

        return connection


    def getConnections(self):

        return self.settingsI.ListConnections()


    def getConnectionPath(self, uuid):

        connection = None

        for c in self.getConnections():

            settings = settingsI.GetSettings()

            if settings['connection']['uuid'] == uuid:
                connection = c
                break

        return connection


    def getActiveConnection(self, path):

        connection = None
        nmdph = DbusPropertiesHelper('/org/freedesktop/NetworkManager', self.dbusHelper, 'org.freedesktop.NetworkManager')

        for a in nmdph.get('ActiveConnections'):

            acdph = DbusPropertiesHelper(a, self.dbusHelper, 'org.freedesktop.NetworkManager.Connection.Active')

            if acdph.get('Connection') == path:
                connection = a
                break

        return connection


    def activateVpn(self, connection, specific_object):

        self.networkManagerI.ActivateConnection(connection, "/", specific_object)


    def isConnectionActive(self, connectionPath):

        c = self.getActiveConnection(connectionPath)

        return c != None


    def activateVpnIf(self):

        baseConnectionPath = self.findConnection(self.interfaceQuery)
        baseConnected = self.isConnectionActive(baseConnectionPath)
        
        while (baseConnected is False):
            logging.debug("waiting for base connection")
            time.sleep(10)
            baseConnected = self.isConnectionActive(baseConnectionPath)

        baseActiveConnection = self.getActiveConnection(baseConnectionPath)
        vpnConnectionPath = self.findConnection(self.vpnQuery)
        vpnConnected = self.isConnectionActive(vpnConnectionPath)

        if (vpnConnected is False):

            self.activateVpn(vpnConnectionPath, baseActiveConnection)
            connected = self.isConnectionActive(vpnConnectionPath)


    def startVpnMonitor(self):

        self.activateVpnIf()
        self.dbusHelper.addReceiver(self.vpnConnectionHandler, "org.freedesktop.NetworkManager.VPN.Connection", "VpnStateChanged")
        gobject.MainLoop().run()


    def vpnConnectionHandler(self, *args, **kwargs):

        state = args[0]
        logging.debug("state %s", state)

        if ((state == NetworkManagerHelper.FAILED) or (state == NetworkManagerHelper.DISCONNECTED)):
        
            self.activateVpnIf()



if __name__ == "__main__":

    logging.basicConfig(level=logging.ERROR)

    if(len(sys.argv) != 3):

        print "Usage: vpnRestart  "
        sys.exit(1)

    interfaceQuery = sys.argv[1]
    vpnQuery = sys.argv[2]

    networkManagerHelper = NetworkManagerHelper(interfaceQuery, vpnQuery)
    baseConnectionPath = networkManagerHelper.findConnection(interfaceQuery)
    logging.debug(baseConnectionPath)

    if(baseConnectionPath is None):

        print "Interface id " + interfaceQuery + " not found."
        sys.exit(1)

    vpnConnectionPath = networkManagerHelper.findConnection(vpnQuery)
    logging.debug(vpnConnectionPath)

    if(vpnConnectionPath is None):

        print "Vpn id " + vpnQuery + " not found."
        sys.exit(1)

    networkManagerHelper.startVpnMonitor()

Wednesday Sep 14, 2011

interview mistakes 101: overthinking the problem - binary tree flattening

i recently blew an interview with a major company. i had to pseudo-code on a (live) shared doc with my phone in the crook of my neck. problem: flatten a binary tree. it went down hill from there (on this problem). i'm pretty sure (now) that the guy wanted to see this:

	private static <T> DoublyLinkedList<T> flatten(BinaryTreeNode<T> btn) {
		
		DoublyLinkedList<T> dll = new DoublyLinkedList<T>();
		
		if(btn != null) {
		
			dll.append(flatten(btn.getLeftChild()));
			dll.add(btn.getValue());
			dll.append(flatten(btn.getRightChild()));
		}
		
		return dll;
	}
demonstrate recursion, step through the code, talk about performance

instead, my compiler class shot through my head and i started talking about the strategy and visitor patterns. why would we want to solidify the traversal pattern (left, node, right) or the output (doubly linked list)? he didn't know what the strategy pattern was. i started stumbling and stuttering, knowing we had fixed time. because i had mentioned the strategy pattern i put some temporary code in but ended up ignoring it, and then had difficulty thinking through the recursion (my head was filed with abstractions). so, in my post mortem of the interview i designed the oo solution i would have wanted to see were i the interviewer. you can download it here (which includes the above complete solution), but here are the key parts:

public class BinaryTree<T> {

	
	private BinaryTreeNode<T> root;
	
	
	public BinaryTree(BinaryTreeNode<T> root) {
		
		this.root = root;
	}
	
	
	public <C> C accept(Visitor<C, T> v, Strategy s) {
		
		s.traverse(root, v);
		
		return v.getResult();
	}
}

public interface Visitor<COL, T> {

	void visitValue(BinaryTreeNode<T> node);
	COL getResult();
}

public interface Strategy {

	/**
	 * @param node may be null
	 */
	<COL, T> COL traverse(BinaryTreeNode<T> node, Visitor<COL, T> v);
}

public class LmrStrategy implements Strategy {

	
	public static final LmrStrategy SINGLETON = new LmrStrategy();
	
	
	private LmrStrategy(){}
	
	
	@Override
	public <COL, T> COL traverse(BinaryTreeNode<T> node, Visitor<COL, T> v) {
		
		if(node != null) {
			
			traverse(node.getLeftChild(), v);
			v.visitValue(node);
			traverse(node.getRightChild(), v);
		}
		
		return v.getResult();
	}

}

public class RmlStrategy implements Strategy {

	
	public static final RmlStrategy SINGLETON = new RmlStrategy();
	
	
	private RmlStrategy(){}
	
	
	@Override
	public <COL, T> COL traverse(BinaryTreeNode<T> node, Visitor<COL, T> v) {
		
		if(node != null) {
			
			traverse(node.getRightChild(), v);
			v.visitValue(node);
			traverse(node.getLeftChild(), v);
		}
		
		return v.getResult();
	}

}

public class DoublyLinkedListVisitor<T> implements Visitor<DoublyLinkedList<T>, T> {

	
	private DoublyLinkedList<T> dll;
	
	
	public DoublyLinkedListVisitor() {
		
		dll = new DoublyLinkedList<T>();
	}

	@Override
	public void visitValue(BinaryTreeNode<T> node) {
		
		dll.add(node.getValue());
	}

	@Override
	public DoublyLinkedList<T> getResult() {
		
		return dll;
	}

}

public class StringVisitor<T> implements Visitor<String, T> {

	
	private StringBuilder sb;
	
	
	public StringVisitor() {
		
		sb = new StringBuilder();
	}


	@Override
	public void visitValue(BinaryTreeNode<T> node) {
		
		sb.append(node.getValue());
	}

	@Override
	public String getResult() {
		
		return sb.toString();
	}

}

Monday Jan 24, 2011

Cyber-Sleuth

cyber security is becoming a hot topic, so i thought i'd write a few notes

  • be proactive
    • hardened os (OpenBSD)
    • minimal installs/applications
    • firewalls
    • logging and alerting sniffer (snort)
    • acl - file, network (selinux)
  • forensics
    • logs
    • live sniffer (tcpdump)
    • various tools (lastlog, modified dates)
    • make a copy for later inspection, but work to get back up immediately
  • hot swap with recent backup

Thursday Jan 06, 2011

MatchMaker

just put a new web application out - MatchMaker. it's a crowd source dating application. hope you enjoy it. if you don't like the initial warning, you can access it here

Monday Dec 13, 2010

hints for grails jquery ajaj

  <head>
<gui:resources components="autoComplete"/>
<g:javascript library="jquery" plugin="jquery"/>
</head>
Config.groovy
grails.views.javascript.library="jquery"

Tuesday Nov 30, 2010

Pilot's Alphabet Test (Groovy Edition)

package net.chrislacy.pilot


class PilotAlphabetTest {
	
	
	def MAP = [ 'A':"Alpha", 'B':"Bravo", 'C':"Charlie", 'D':"Delta", 'E':"Echo", 'F':"Foxtrot", 'G':"Golf", 
		'H':"Hotel", 'I':"India", 'J':"Julliett", 'K':"Kilo", 'L':"Lima", 'M':"Mike", 'N':"November", 
		'O':"Oscar", 'P':"Papa", 'Q':"Quebec", 'R':"Romeo", 'S':"Sierra", 'T':"Tango", 'U':"Uniform", 
		'V':"Victor", 'W':"Whiskey", 'X':"X-ray", 'Y':"Yankee", 'Z':"Zulu" ]
	
	
	def main() {
		
		InputStreamReader c = new InputStreamReader(System.in)
		BufferedReader inr = new BufferedReader(c)
		
		def cl = MAP.keySet() as LinkedList
		Collections.shuffle(cl, new Random())
		
		cl.each {
			
			println(it)
			String answer = MAP.get(it)
			
			if(!inr.readLine().equalsIgnoreCase(answer)) {
				
				println(answer)
			}
		}
	}
}


def pat = new PilotAlphabetTest()
pat.main()

Pilot's Alphabet Test

package net.chrislacy.pilot;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;



public class PilotAlphabet {

	
	private static final Map MAP = new HashMap();
	
	
	static {
		
		MAP.put('A', "Alpha");
		MAP.put('B', "Bravo");
		MAP.put('C', "Charlie");
		MAP.put('D', "Delta");
		MAP.put('E', "Echo");
		MAP.put('F', "Foxtrot");
		MAP.put('G', "Golf");
		MAP.put('H', "Hotel");
		MAP.put('I', "India");
		MAP.put('J', "Julliett");
		MAP.put('K', "Kilo");
		MAP.put('L', "Lima");
		MAP.put('M', "Mike");
		MAP.put('N', "November");
		MAP.put('O', "Oscar");
		MAP.put('P', "Papa");
		MAP.put('Q', "Quebec");
		MAP.put('R', "Romeo");
		MAP.put('S', "Sierra");
		MAP.put('T', "Tango");
		MAP.put('U', "Uniform");
		MAP.put('V', "Victor");
		MAP.put('W', "Whiskey");
		MAP.put('X', "X-ray");
		MAP.put('Y', "Yankee");
		MAP.put('Z', "Zulu");
	}
	
	
	public static void main(String[] args) throws Exception {
		
		InputStreamReader converter = new InputStreamReader(System.in);
		BufferedReader in = new BufferedReader(converter);
		
		Character[] ca = MAP.keySet().toArray(new Character[]{});
		List cl = Arrays.asList(ca);
		Collections.shuffle(cl, new Random());
		
		for(Character c : cl) {
			
			System.out.println(c);
			String line = in.readLine();
			String answer = MAP.get(c);
			
			if(!line.equalsIgnoreCase(answer)) {
				
				System.out.println(answer);
			}
		}
	}
}

Wednesday Sep 29, 2010

gRest

i've made available the start of a grails application that exposes a database as a RESTful web service. download

Thursday Aug 26, 2010

coc rest - now with schemas!

  • post whatever, in whatever format
    • retrieve in whatever format
  • add schema before/after if you want (in language of choice - sql, Java, groovy, xml, etc)
  • add security if you want (over coc)
impl
  • key/value cache with storage back
  • translators
  • cross kingdom impl to support favorite deploy (war, cgi, etc)

Tuesday Aug 24, 2010

the vm

i predict that a new vm will emerge

  • designed for the cloud
  • non proprietary
    • may abstract jvm and/or .net
  • @see xmlvm
  • program to any supported api
    • all open source apis become immediately available
  • will be optimised for: grails, rails, scheme, and/or erlang

Tuesday Jul 27, 2010

802.11s - I am disappoint

I continue to have high hopes for 802.11s and more advanced networking in general. ISPs are no longer needed. All we need are ways to securely and fairly share our connectivity. Imagine you're using your netbook and want to access google, but there's no hotspot nearby. Luckily, there's a guy on his smart phone 100 feet away, and from there he has a signal to a company's wifi (on which he's making the call). That company has a large antenna that reaches google.

I see lots of potential here. You can exchange bandwidth for equal bandwidth, and receive cash if you run a surplus. Municipalities would only need one connection to internet backbone instead of running wires to each residence. Anyone can run a website/server. It's the future.

Saturday Jun 26, 2010

object translators

in the year 2000, the buzz will be object translators, aka, property editors, aka closures, aka un/marshallers, aka de/serializers, aka reflected methods, etc. and everyone will conform to a standard api

we'll have libraries of translators, too; and we'll define the rules by which a given translator is chosen for conversion between types. and we'll have translators that don't have return values, and translators that take multiple values, etc

and what we'll do, is, we'll pipe data between these translators and translator libraries. REST will be piping data from a web request to a translator that converts http messages to sql (with maybe JSON or XML or AMF in between, plus validation/exception handling and security)

but we'll add these "plus" features (exception handling, security, caching, etc) with aop and additional translators/libraries

music test

package net.chrislacy.music.test;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;

public class MusicTest {
	
	
	private static final double[] NOTES = { 261.626, 293.665, 329.628, 349.228, 391.995, 440.000, 493.883, 523.251 };
	private static final Set<Integer> INCLUDE = new HashSet<Integer>();
	private static final double VOLUME = 0.03;
	private static final long LENGTH_MS = 1500;
	
	static {
		
		INCLUDE.add(1);
		INCLUDE.add(3);
		//INCLUDE.add(4);
		INCLUDE.add(5);
		//INCLUDE.add(8);
	}

	public static void main(String[] args) throws Throwable {
		
		// TODO add fails to "more often test" list
		// print solution after x (3) wrong guesses
		
		while(true) {
			
			List<Integer> notes = playRandomPhrase(3, VOLUME);
			InputStreamReader converter = new InputStreamReader(System.in);
			BufferedReader in = new BufferedReader(converter);
			
			boolean shouldRepeat = true;
			
			while(shouldRepeat) {
				
				String line = in.readLine();
				int index = 0;
				boolean passed = true;
				
				inner:
				for(Integer n : notes) {
					
					if(line.length() != notes.size() || Integer.parseInt(line.charAt(index++) + "") != n) {
						
						System.out.println("nope");
						playPhrase(VOLUME, createSimilarNotes(LENGTH_MS, 100, hertzFromOneBased(notes)));
						passed = false;
						break inner;
					}
				}
				
				shouldRepeat = !passed;
			}
		}
	}
	
	private static double[] hertzFromOneBased(List<Integer> oneBased) {
		
		double[] hertzs = new double[oneBased.size()];
		int index = 0;
		
		for(Integer oneB : oneBased) {
			
			hertzs[index++] = NOTES[oneB - 1];
		}
		
		return hertzs;
	}
	
	private static List<Integer> playRandomPhrase(int length, double volume) {

		List<Integer> result = new LinkedList<Integer>();
		double[] hertzs = new double[length];
		
		result.add(1);
		hertzs[0] = NOTES[0];
		
		for(int ii=1; ii<length; ii++) {
			
			int cur = randomIntLessThan(NOTES.length);
			int oneBasedCur = cur + 1;
			
			while(!INCLUDE.contains(oneBasedCur)) {
				
				cur = randomIntLessThan(NOTES.length);
				oneBasedCur = cur + 1;
			}
			
			result.add(oneBasedCur);
			hertzs[ii] = NOTES[cur];
		}
		
		playPhrase(volume, createSimilarNotes(LENGTH_MS, 100, hertzs));
		
		return result;
	}
	
	private static int randomIntLessThan(int max) {
		
		double r = Math.random();
		
		return (int) Math.round(r * max);
	}
	
	private static ComplexNote[] createSimilarNotes(long length, int relativeVolume, double... hertz) {
		
		ComplexNote[] result = new ComplexNote[hertz.length];
		
		for(int ii=0; ii<hertz.length; ii++) {
			
			result[ii] = new ComplexNote(hertz[ii], length, relativeVolume);
		}
		
		return result;
	}
	
	private static byte[] createOneWave(int numberOfBytes, double maxHeight) {
		
		byte[] oneWave = new byte[numberOfBytes];
		
		for(int i=0; i<numberOfBytes; i++) {
			
			double fractionalPos = ((double)i*2) / numberOfBytes;
			double angle = fractionalPos * Math.PI;
			double sineVal = Math.sin(angle);
			Double volSine = sineVal * maxHeight;
			byte b = volSine.byteValue();
			oneWave[i] = b;
		}
		
		return oneWave;
	}
	
	private static byte[] makeWaveTwoChannel(byte[] oneWave) {
		
		byte[] stereoWave = new byte[oneWave.length * 2];
		
		for(int i=0; i<oneWave.length; i++) {
			
			int stereoPos = i*2;
			stereoWave[stereoPos] = stereoWave[stereoPos+1] = oneWave[i];
		}
		
		return stereoWave;
	}
	
	private static byte[] repeatWave(byte[] original, int numberOfWaves) {
		
		byte[] multipleStereoWaves = new byte[original.length * numberOfWaves];
		
		for(int i=0; i < numberOfWaves; i++) {
			
			System.arraycopy(original, 0, multipleStereoWaves, original.length * i, original.length);
		}
		
		return multipleStereoWaves;
	}
	
	private static byte[] createMultipleStereoWaves(int bytesPerWave, double volume, int numberOfWaves) {
		
		byte[] oneWave = createOneWave(bytesPerWave, volume);
		byte[] stereoWave = makeWaveTwoChannel(oneWave);
		
		return repeatWave(stereoWave, numberOfWaves);
	}
	
	private static Clip createClip(AudioInputStream ais) {
		
		Clip clip;
		
		try {
			
			clip = AudioSystem.getClip();
			clip.open(ais);
			clip.setFramePosition(0);
		}
		catch (Exception e) {

			throw new RuntimeException(e);
		}
		
		return clip;
	}
	
	/**
	 * @param volume 1.000104 min vol headphones @ 220 hz
	 */
	private static AudioInputStream createAudioInputStream(double volume, ComplexNote... notes) {
		
		float bytesPerSecond = 48000f;
		
		AudioFormat af = new AudioFormat(bytesPerSecond, 
				8, // sample size in bits
				2, // channels
				true, // signed
				false // bigendian
		);
		
		List<byte[]> waveList = new LinkedList<byte[]>();
		int finalLength = 0;
		
		for(ComplexNote note : notes) {
		
			Double bpw = bytesPerSecond/note.getHertz();
			int bytesPerWave = bpw.intValue();
			int numberOfWaves = 800/bpw.intValue() + 5; // 763
			byte[] multipleStereoWaves = createMultipleStereoWaves(bytesPerWave, note.getRelativeVolume() * volume, numberOfWaves);
			
			int numBytesNeeded = ((Float) (bytesPerSecond * (note.getLength()/1000))).intValue();
			byte[] noteBuffer = new byte[numBytesNeeded];
			int repeatNum = numBytesNeeded / multipleStereoWaves.length;
			int ii=0;
			
			for(; ii<repeatNum; ii++) {
				
				System.arraycopy(multipleStereoWaves, 0, noteBuffer, multipleStereoWaves.length * ii, multipleStereoWaves.length);
			}
			
			System.arraycopy(multipleStereoWaves, 0, noteBuffer, multipleStereoWaves.length * ii, numBytesNeeded % multipleStereoWaves.length);
			
			waveList.add(noteBuffer);
			finalLength += noteBuffer.length;
		}
		
		byte[] finalBa = new byte[finalLength];
		int index = 0;
		
		for(byte[] cur : waveList) {
			
			System.arraycopy(cur, 0, finalBa, index, cur.length);
			index = index + cur.length;;
		}
			
		return new AudioInputStream(new ByteArrayInputStream(finalBa), af, finalBa.length/2);
	}
	
	private static void playPhrase(double volume, ComplexNote... notes) {
		
		Clip clip = createClip(createAudioInputStream(volume, notes));
		clip.loop(0);
		clip.drain();
		clip.flush();
		clip.close();
	}

}

Wednesday Jun 23, 2010

SingleResourceResolver

I don't know what others are doing for this, but try this for your rest implementations:

package net.chrislacy.webapp.util;

import java.util.Locale;

import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;

public class SingleViewResolver implements ViewResolver {

	
	private View view;
	
	
	public SingleViewResolver(View view) {
		
		this.view = view;
	}
	
	@Override
	public View resolveViewName(String viewName, Locale locale) throws Exception {
		
		return view;
	}

}

for example:
	<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
		<property name="mediaTypes">
			<map>
				<entry key="json" value="application/json" />
				<entry key="xml" value="application/xml" />
				<entry key="html" value="text/html" />
			</map>
		</property>
		<property name="viewResolvers">
			<list>
				<bean class="net.chrislacy.webapp.util.SingleViewResolver">
					<constructor-arg name="view">
						<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
					</constructor-arg>
				</bean>
				<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
					p:prefix="/WEB-INF/jsp/" p:suffix=".jsp" />
			</list>
		</property>
	</bean>

Tuesday Jun 22, 2010

Integration Testing Spring Web Applications through DispatcherServlet

import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.*;
import static org.springframework.web.util.WebUtils.*;

import java.util.Enumeration;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.chrislacy.utils.c.EasyEnumeration;

import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

public class DispatcherTestHelper {

	
	private DispatcherTestHelper() {}
	
	
	@SuppressWarnings("unchecked")
	public static HttpServletResponse test(String configLocation, String method, String path) throws Throwable {
		
		DispatcherServlet ds = new DispatcherServlet();
		ds.setContextConfigLocation(configLocation);
		
		ServletConfig sc = mock(ServletConfig.class);
		Enumeration e = mock(Enumeration.class);
			
		when(sc.getInitParameterNames()).thenReturn(e);
		ServletContext scon = mock(ServletContext.class);
		when(scon.getInitParameterNames()).thenReturn(e);
		when(scon.getAttributeNames()).thenReturn(e);
		when(sc.getServletContext()).thenReturn(scon);
		
		ds.init(sc);
		
		WebApplicationContext wac = ds.getWebApplicationContext();
		when(scon.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE)).thenReturn(wac);
		
		HttpServletRequest hsr = mock(HttpServletRequest.class);
		when(hsr.getMethod()).thenReturn(method);
		
		when(hsr.getAttribute(INCLUDE_REQUEST_URI_ATTRIBUTE)).thenReturn(path);
		when(hsr.getAttribute(INCLUDE_CONTEXT_PATH_ATTRIBUTE)).thenReturn(path);
		when(hsr.getAttribute(INCLUDE_SERVLET_PATH_ATTRIBUTE)).thenReturn(path);
		when(hsr.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE)).thenReturn(wac);
		when(hsr.getAttributeNames()).thenReturn(new EasyEnumeration(INCLUDE_REQUEST_URI_ATTRIBUTE, 
INCLUDE_CONTEXT_PATH_ATTRIBUTE, INCLUDE_SERVLET_PATH_ATTRIBUTE, WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE));
		when(hsr.getRequestURI()).thenReturn(path);
		RequestDispatcher rd = mock(RequestDispatcher.class);
		when(hsr.getRequestDispatcher(anyString())).thenReturn(rd);
		HttpServletResponse hsres = mock(HttpServletResponse.class);
		ds.service(hsr, hsres);
		
		verify(rd).include(hsr, hsres);
		
		return hsres;
	}
}


	@Test
	public void test() throws Throwable {
		HttpServletResponse hsres = DispatcherTestHelper.test("file:src/main/webapp/WEB-INF/spring/*-config.xml", "GET", "/welcome");
		System.out.println(hsres);
	}

Calendar

Feeds

Search

Links

Navigation

Referrers