diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0c2792e --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/target +/build +/.classpath +/.settings +/.project diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..13b3083 --- /dev/null +++ b/pom.xml @@ -0,0 +1,176 @@ + + 4.0.0 + com.gruter + gruter-common + 0.9.0 + + + 6.1.24 + 1.6.0 + 1.2.14 + 0.21.0 + 3.3.1 + 0.6.0 + 4.8 + + + + + babokim + gruter + + + + + build + src/java + src/test + + + src/java + + **/*.java + + + + + + src/test + + **/*.java + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.6 + 1.6 + UTF-8 + + + + + + + + + junit + junit + ${junit.version} + test + + + + commons-collections + commons-collections + 3.2.1 + + + commons-dbcp + commons-dbcp + 1.4 + + + commons-httpclient + commons-httpclient + 3.0.1 + + + commons-io + commons-io + 1.4 + + + commons-lang + commons-lang + 2.4 + + + commons-net + commons-net + 1.4.1 + + + oro + oro + + + + + org.apache.httpcomponents + httpclient + 4.0.1 + + + org.mortbay.jetty + jetty + ${jetty.version} + + + log4j + log4j + ${log4j.version} + + + org.slf4j + slf4j-log4j12 + ${slf4j.version} + + + org.apache.thrift + thrift + ${thrift.version} + system + ${basedir}/lib/libthrift-${thrift.version}.jar + + + + org.apache.hadoop + hadoop-common + ${hadoop.version} + true + system + ${basedir}/lib/hadoop-common-${hadoop.version}.jar + + + org.apache.hadoop + hadoop-hdfs + ${hadoop.version} + true + system + ${basedir}/lib/hadoop-hdfs-${hadoop.version}.jar + + + org.apache.hadoop + hadoop-mapred + ${hadoop.version} + true + system + ${basedir}/lib/hadoop-mapred-${hadoop.version}.jar + + + org.apache.hadoop + hadoop-mapred-tools + ${hadoop.version} + true + system + ${basedir}/lib/hadoop-mapred-tools-${hadoop.version}.jar + + + org.apache.zookeeper + zookeeper + ${zookeeper.version} + + + jline + jline + + + + + diff --git a/src/test/com/gruter/common/http/CommonHttpServerTestCase.java b/src/test/com/gruter/common/http/CommonHttpServerTestCase.java new file mode 100644 index 0000000..19b455e --- /dev/null +++ b/src/test/com/gruter/common/http/CommonHttpServerTestCase.java @@ -0,0 +1,212 @@ +package com.gruter.common.http; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.http.HttpServlet; + +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpHead; +import org.apache.http.client.methods.HttpOptions; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpPut; +import org.apache.http.client.methods.HttpTrace; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.impl.client.DefaultHttpClient; + +/** + * @author Daegeun Kim + */ +public abstract class CommonHttpServerTestCase implements FilterContainer { + private static final String DEFAULT_WEB_CONTEXT_PATH = "default_context_path"; + private static final String DEFAULT_HOSTNAME = "127.0.0.1"; + private static final int DEFAULT_PORT = 8100; + + private String webContextPath; + protected String hostname; + protected int port; + protected CommonHttpServer server; + private boolean running; + + protected CommonHttpServerTestCase() { + this(DEFAULT_WEB_CONTEXT_PATH, DEFAULT_HOSTNAME, DEFAULT_PORT); + } + + protected CommonHttpServerTestCase(String webContextPath) { + this(webContextPath, DEFAULT_HOSTNAME, DEFAULT_PORT); + } + + protected CommonHttpServerTestCase(String webContextPath, String hostname, int port) { + this.webContextPath = webContextPath; + this.hostname = hostname; + this.port = port; + } + + protected void initServer() throws IOException { + if (server == null) { + server = new CommonHttpServer(getWebContextPath(), getHostname(), getPort(), false); + } + } + + /** + * 서블릿 추가 + * @param name + * @param pathSpec + * @param clazz + */ + public void addServlet(String name, String pathSpec, Class clazz) { + server.addServlet(name, pathSpec, clazz); + } + + /* (non-Javadoc) + * @see com.gruter.common.http.FilterContainer#addFilter(java.lang.String, java.lang.String, java.util.Map) + */ + public void addFilter(String name, String classname, Map parameters) { + server.addFilter(name, classname, parameters); + } + + /* (non-Javadoc) + * @see com.gruter.common.http.FilterContainer#addGlobalFilter(java.lang.String, java.lang.String, java.util.Map) + */ + public void addGlobalFilter(String name, String classname, Map parameters) { + server.addGlobalFilter(name, classname, parameters); + } + + /** + * 지정한 hostname 과 port 를 기반으로 서버를 구동한다. + * @throws IOException + */ + protected void runServer() throws IOException { + if (running == false && server == null) { + initServer(); + } + if (running == false) { + server.start(); + running = true; + } + } + + /** + * 구동된 서버를 중지시킨다. + * @throws Exception + */ + protected void stopServer() throws Exception { + if (server == null) { + throw new Exception("server is not running"); + } + server.stop(); + } + + @SuppressWarnings("unchecked") + protected

P requestToServer(String method, String path) throws Exception { + if (isRunning() == false) { + runServer(); + } + + DefaultHttpClient client = new DefaultHttpClient(); + HttpUriRequest request = invokeMethod(method, getPageURI(path)); + Page page = new Page(new WebResponse(client.execute(request))); + return (P) page; + /* + // HTMLUnit 으로 작성했다가 필요한 Library 가 워낙 많아서 주석 처리하고 httpcomponent 4.x 으로 변경하고 하위에 inner class 만들었습니다. + // maven 을 사용하면 test 용 library 는 제외시키기 편한데 ant 는 건드려야 할 것이 많아서 급 수정 + WebClient client = new WebClient(); + WebRequest request = new WebRequest(new URL(getPageURI(path)), HttpMethod.valueOf(method.toUpperCase())); + try { + return (P) client.getPage(request); + } catch (FailingHttpStatusCodeException e) { + Page page = new HtmlPage(request.getUrl(), e.getResponse(), client.getCurrentWindow()); + return (P) page; + } catch (MalformedURLException e) { + throw e; + } catch (IOException e) { + throw e; + } finally { + client.closeAllWindows(); + } + */ + } + + private HttpUriRequest invokeMethod(String method, String page) { + Map> methods = new HashMap>(); + methods.put("GET", HttpGet.class); + methods.put("PUT", HttpPut.class); + methods.put("POST", HttpPost.class); + methods.put("OPTIONS", HttpOptions.class); + methods.put("HEAD", HttpHead.class); + methods.put("TRACE", HttpTrace.class); + methods.put("DELETE", HttpDelete.class); + try { + return methods.get(method.toUpperCase()).getConstructor(String.class).newInstance(page); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private boolean isRunning() { + return running; + } + + /** + * 테스트에 사용할 URL 문자열을 만든다. + * @param path + * @return + */ + protected String getPageURI(String path) { + return new StringBuilder("http://").append(getAuthority()).append(path).toString(); + } + + protected String getAuthority() { + return getPort() == 80 ? getHostname() : getHostname() + ":" + getPort(); + } + + protected String getWebContextPath() { + return webContextPath; + } + + protected String getHostname() { + return hostname; + } + + protected int getPort() { + return port; + } + + + /** + * HtmlUnit 의 Page class 를 코드변경없이 사용하고자 동일한 이름의 클래스로 필요한 것만 작성 + */ + protected static class Page { + WebResponse response; + + Page(WebResponse response) { + this.response = response; + } + + public WebResponse getWebResponse() { + return response; + } + } + + /** + * HtmlUnit 의 WebResponse class 를 코드변경없이 사용하고자 동일한 이름의 클래스로 필요한 것만 작성 + */ + protected static class WebResponse { + HttpResponse response; + + WebResponse(HttpResponse response) { + this.response = response; + } + + public String getResponseHeaderValue(String name) { + return response.getFirstHeader(name).getValue(); + } + + public int getStatusCode() { + return response.getStatusLine().getStatusCode(); + } + } +} diff --git a/src/test/com/gruter/common/http/TestCommonHttpServer.java b/src/test/com/gruter/common/http/TestCommonHttpServer.java new file mode 100644 index 0000000..785f343 --- /dev/null +++ b/src/test/com/gruter/common/http/TestCommonHttpServer.java @@ -0,0 +1,118 @@ +package com.gruter.common.http; + +import static org.hamcrest.CoreMatchers.is; + +import java.io.IOException; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.zookeeper.server.ServerConfig; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import com.gruter.common.zk.ZooKeeperLocalServer; + +/** + * @author Daegeun Kim + */ +public class TestCommonHttpServer extends CommonHttpServerTestCase { + public TestCommonHttpServer() { + super("common_webapps"); + } + + @Before + public void before() throws Exception { + initServer(); + } + + @After + public void after() throws Exception { + stopServer(); + } + + @Test + public void test200() throws Exception { + Page page = requestToServer("GET", "/zktree.html"); + + Assert.assertThat(200, is(page.getWebResponse().getStatusCode())); + } + + @Test + public void test404() throws Exception { + Page page = requestToServer("GET", "/12312310293i81093jfpawejfiwoejfowaiej.html"); + + Assert.assertThat(404, is(page.getWebResponse().getStatusCode())); + } + + @Test + public void testServlet() throws Exception { + addServlet("test-servlet", "/test", TestServlet.class); + Page page = requestToServer("GET", "/test"); + + Assert.assertThat(200, is(page.getWebResponse().getStatusCode())); + } + + @Test + public void testFilter() throws Exception { + addFilter("test-filter", TestFilter.class.getName(), null); + Page page = requestToServer("GET", "/zktree.html"); + + Assert.assertThat(200, is(page.getWebResponse().getStatusCode())); + Assert.assertThat(TestFilter.class.getName(), is(getHeader(page, "X-Filter"))); + } + + @Test + public void testGlobalFilter() throws Exception { + addServlet("test-servlet", "/test", TestServlet.class); + addGlobalFilter("test-filter", TestFilter.class.getName(), null); + Page page = requestToServer("GET", "/test"); + + Assert.assertThat(200, is(page.getWebResponse().getStatusCode())); + Assert.assertThat(TestFilter.class.getName(), is(getHeader(page, "X-Filter"))); + } + + private String getHeader(Page page, String headerName) { + return page.getWebResponse().getResponseHeaderValue(headerName); + } + + /** + * 테스트용으로 사용할 Filter + */ + public static class TestFilter implements Filter { + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + ((HttpServletResponse) response).addHeader("X-Filter", TestFilter.class.getName()); + } + + @Override + public void destroy() { + } + + @Override + public void init(FilterConfig arg0) throws ServletException { + } + } + + /** + * 테스트용으로 사용할 Servlet + */ + public static class TestServlet extends HttpServlet { + private static final long serialVersionUID = -1990697247757359833L; + + @Override + protected void service(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + response.setContentType("text/html; charset=UTF-8"); + } + } +} diff --git a/src/test/com/gruter/common/zk/TestZKManagerWebServer.java b/src/test/com/gruter/common/zk/TestZKManagerWebServer.java new file mode 100644 index 0000000..2362194 --- /dev/null +++ b/src/test/com/gruter/common/zk/TestZKManagerWebServer.java @@ -0,0 +1,43 @@ +package com.gruter.common.zk; + +import static org.hamcrest.CoreMatchers.is; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import com.gruter.common.http.CommonHttpServerTestCase; +import com.gruter.common.http.ZKControllerServlet; + +/** + * @author Daegeun Kim + */ +public class TestZKManagerWebServer extends CommonHttpServerTestCase { + public TestZKManagerWebServer() { + super("common_webapps"); + } + + @Before + public void before() throws Exception { + initServer(); + } + + @After + public void after() throws Exception { + stopServer(); + } + + @Test + public void testZookeeperServlet() throws Exception { + ZooKeeperLocalServer zkserver = new ZooKeeperLocalServer(); + zkserver.run(21333); + + addServlet("zk-servlet", "/zookeeper", ZKControllerServlet.class); + Page page = requestToServer("GET", "/zookeeper?action=GetZKNodeDetail&zkservers=127.0.0.1%3A21333&dir=%2F"); + + zkserver.shutdown(); + Assert.assertThat(200, is(page.getWebResponse().getStatusCode())); + //TODO: 임의의 znode 와 data 를 추가하고 넘겨받은 json 결과와 data 비교 검증 필요. + } +} diff --git a/src/test/com/gruter/common/zk/ZooKeeperLocalServer.java b/src/test/com/gruter/common/zk/ZooKeeperLocalServer.java new file mode 100644 index 0000000..0177128 --- /dev/null +++ b/src/test/com/gruter/common/zk/ZooKeeperLocalServer.java @@ -0,0 +1,38 @@ +package com.gruter.common.zk; + +import java.io.File; +import java.io.IOException; +import java.util.UUID; + +import org.apache.zookeeper.server.ServerConfig; +import org.apache.zookeeper.server.ZooKeeperServerMain; + +/** + * zookeeper 는 잘 몰라서 제대로 짠 걸까요. :-) + * @author Daegeun Kim + */ +public class ZooKeeperLocalServer extends ZooKeeperServerMain { + private File tempDir = null; + + public void run(int clientPort) throws IOException { + String tempdir = System.getProperty("java.io.tmpdir"); + tempDir = new File(tempdir, UUID.randomUUID().toString()); + tempDir.mkdirs(); + final ServerConfig config = new ServerConfig(); + config.parse(new String[] { "" + clientPort, tempDir.getAbsolutePath() }); + new Thread(new Runnable() { + public void run() { + try { + runFromConfig(config); + } catch (IOException e) { + } + } + }).start(); + } + + @Override + public void shutdown() { + super.shutdown(); + tempDir.delete(); + } +}