Browse Source

Update Sabina benchmark

jamming 10 years ago
parent
commit
e36c7be182

+ 18 - 12
frameworks/Java/sabina/pom.xml

@@ -1,3 +1,17 @@
+<!--
+ ! Copyright © 2015 Juan José Aguililla. All rights reserved.
+ !
+ ! Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ ! except in compliance with the License. You may obtain a copy of the License at
+ !
+ !     http://www.apache.org/licenses/LICENSE-2.0
+ !
+ ! Unless required by applicable law or agreed to in writing, software distributed under the
+ ! License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ ! either express or implied. See the License for the specific language governing permissions
+ ! and limitations under the License.
+ !-->
+
 <project
     xmlns="http://maven.apache.org/POM/4.0.0"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
@@ -22,8 +36,7 @@
 
         <db.host>localhost</db.host>
 
-        <sabina-version>1.1.0</sabina-version>
-        <mysql-connector-version>5.1.28</mysql-connector-version>
+        <sabina-version>1.1.1</sabina-version>
     </properties>
 
     <repositories>
@@ -77,26 +90,19 @@
         <dependency>
             <groupId>mysql</groupId>
             <artifactId>mysql-connector-java</artifactId>
-            <version>${mysql-connector-version}</version>
+            <version>5.1.28</version>
         </dependency>
 
-        <dependency>
-            <groupId>junit</groupId>
-            <artifactId>junit</artifactId>
-            <version>4.11</version>
-            <scope>test</scope>
-        </dependency>
         <dependency>
             <groupId>org.testng</groupId>
             <artifactId>testng</artifactId>
-            <version>6.8.8</version>
+            <version>6.8.21</version>
             <scope>test</scope>
         </dependency>
-        <!--testCompile 'org.testng:testng:6.8.8'-->
         <dependency>
             <groupId>org.apache.httpcomponents</groupId>
             <artifactId>fluent-hc</artifactId>
-            <version>4.4</version>
+            <version>4.3.3</version>
             <scope>test</scope>
         </dependency>
     </dependencies>

+ 1 - 1
frameworks/Java/sabina/setup.sh

@@ -1,4 +1,4 @@
 #!/bin/bash
 
 mvn clean package -Ddb.host=${DBHOST}
-${JAVA_HOME}/bin/java -jar target/sabina-1.0.0-SNAPSHOT.jar &
+${JAVA_HOME}/bin/java -jar target/sabina-1.0.0.jar &

+ 47 - 9
frameworks/Java/sabina/src/main/java/sabina/benchmark/Application.java

@@ -1,6 +1,21 @@
+/*
+ * Copyright © 2015 Juan José Aguililla. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+
 package sabina.benchmark;
 
 import static java.lang.Integer.parseInt;
+import static java.lang.System.getProperty;
 import static sabina.Sabina.*;
 import static sabina.content.JsonContent.toJson;
 import static sabina.view.MustacheView.renderMustache;
@@ -8,11 +23,9 @@ import static sabina.view.MustacheView.renderMustache;
 import com.mchange.v2.c3p0.ComboPooledDataSource;
 import sabina.Request;
 
-import java.sql.Connection;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
+import java.sql.*;
 import java.util.*;
+import java.util.Date;
 import java.util.concurrent.ThreadLocalRandom;
 
 import javax.sql.DataSource;
@@ -29,6 +42,7 @@ final class Application {
     private static final DataSource DATA_SOURCE = createSessionFactory ();
     private static final int DB_ROWS = 10000;
 
+    private static final boolean AUTOCOMMIT = getProperty ("sabina.benchmark.autocommit") != null;
     private static final String SELECT_WORLD = "select * from world where id = ?";
     private static final String UPDATE_WORLD = "update world set randomNumber = ? where id = ?";
     private static final String SELECT_FORTUNES = "select * from fortune";
@@ -135,7 +149,8 @@ final class Application {
         final World[] worlds = new World[queries];
 
         try (final Connection con = DATA_SOURCE.getConnection ()) {
-            con.setAutoCommit (false);
+            con.setAutoCommit (AUTOCOMMIT);
+
             final Random random = ThreadLocalRandom.current ();
             final PreparedStatement stmtSelect = con.prepareStatement (SELECT_WORLD);
             final PreparedStatement stmtUpdate = con.prepareStatement (UPDATE_WORLD);
@@ -147,11 +162,33 @@ final class Application {
                     worlds[ii] = new World (rs.getInt (1), rs.getInt (2));
                     stmtUpdate.setInt (1, random.nextInt (DB_ROWS) + 1);
                     stmtUpdate.setInt (2, worlds[ii].id);
-                    stmtUpdate.addBatch ();
+
+                    if (AUTOCOMMIT) {
+                        stmtUpdate.executeUpdate ();
+                    }
+                    else {
+                        stmtUpdate.addBatch ();
+                    }
                 }
             }
-            stmtUpdate.executeBatch ();
-            con.commit ();
+
+            if (!AUTOCOMMIT) {
+                int count = 0;
+                boolean retrying;
+
+                do {
+                    try {
+                        stmtUpdate.executeBatch ();
+                        retrying = false;
+                    }
+                    catch (BatchUpdateException e) {
+                        retrying = true;
+                    }
+                }
+                while (count++ < 10 && retrying);
+
+                con.commit ();
+            }
         }
         catch (SQLException e) {
             e.printStackTrace ();
@@ -181,6 +218,7 @@ final class Application {
         after (Application::addCommonHeaders);
 
         host (SETTINGS.getProperty ("web.host"));
-        start (parseInt (SETTINGS.getProperty ("web.port")));
+        port (SETTINGS.getProperty ("web.port"));
+        start ();
     }
 }

+ 14 - 3
frameworks/Java/sabina/src/main/java/sabina/benchmark/Fortune.java

@@ -1,3 +1,17 @@
+/*
+ * Copyright © 2015 Juan José Aguililla. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+
 package sabina.benchmark;
 
 /**
@@ -13,7 +27,4 @@ final class Fortune {
         this.id = id;
         this.message = message;
     }
-
-    public int getId () { return id; }
-    public String getMessage () { return message; }
 }

+ 14 - 0
frameworks/Java/sabina/src/main/java/sabina/benchmark/Message.java

@@ -1,3 +1,17 @@
+/*
+ * Copyright © 2015 Juan José Aguililla. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+
 package sabina.benchmark;
 
 final class Message {

+ 14 - 0
frameworks/Java/sabina/src/main/java/sabina/benchmark/World.java

@@ -1,3 +1,17 @@
+/*
+ * Copyright © 2015 Juan José Aguililla. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+
 package sabina.benchmark;
 
 final class World {

+ 14 - 0
frameworks/Java/sabina/src/main/resources/server.properties

@@ -1,3 +1,17 @@
+#
+# Copyright \u00A9 2015 Juan Jos\u00E9 Aguililla. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software distributed under the
+# License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+# either express or implied. See the License for the specific language governing permissions
+# and limitations under the License.
+#
+
 web.port = 5050
 web.host = 0.0.0.0
 

+ 92 - 29
frameworks/Java/sabina/src/test/java/sabina/benchmark/ApplicationTest.java

@@ -1,3 +1,17 @@
+/*
+ * Copyright © 2015 Juan José Aguililla. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+
 package sabina.benchmark;
 
 import static org.apache.http.client.fluent.Request.Get;
@@ -13,26 +27,57 @@ import java.util.Scanner;
 
 import com.google.gson.Gson;
 import org.apache.http.HttpResponse;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
[email protected]
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+/**
+ * <p>TODO
+ * Write article about stress test with TestNG (scenarios, combine different tests in scenarios,
+ * adding random pauses...)
+ *
+ * <p>TODO Change assert's order
+ */
 public final class ApplicationTest {
+    private static final int THREADS = 32, EXECUTIONS = 64, WARM_UP = 16;
+
     private static final String ENDPOINT = "http://localhost:5050";
     private static final Gson GSON = new Gson ();
 
-    @org.testng.annotations.BeforeClass @BeforeClass
-    public static void setup () {
+    @BeforeClass public static void setup () {
         main (null);
     }
 
-    @org.testng.annotations.AfterClass @AfterClass
-    public static void close () {
+    @BeforeClass public void warm_up () throws IOException {
+        for (int ii = 0; ii < WARM_UP; ii++) {
+            json ();
+            plaintext ();
+            no_query_parameter ();
+            empty_query_parameter ();
+            text_query_parameter ();
+            zero_queries ();
+            one_thousand_queries ();
+            one_query ();
+            ten_queries ();
+            five_hundred_queries ();
+            fortunes ();
+            no_updates_parameter ();
+            empty_updates_parameter ();
+            text_updates_parameter ();
+            zero_updates ();
+            one_thousand_updates ();
+            one_update ();
+            ten_updates ();
+            five_hundred_updates ();
+        }
+    }
+
+    @AfterClass public static void close () {
         stop ();
     }
 
-    @Test public void json () throws IOException {
+    @Test(threadPoolSize = THREADS, invocationCount = EXECUTIONS)
+    public void json () throws IOException {
         HttpResponse response = get (ENDPOINT + "/json");
         String content = getContent (response);
 
@@ -40,7 +85,8 @@ public final class ApplicationTest {
         assertEquals ("Hello, World!", GSON.fromJson (content, Map.class).get ("message"));
     }
 
-    @Test public void plaintext () throws IOException {
+    @Test(threadPoolSize = THREADS, invocationCount = EXECUTIONS)
+    public void plaintext () throws IOException {
         HttpResponse response = get (ENDPOINT + "/plaintext");
         String content = getContent (response);
 
@@ -48,7 +94,8 @@ public final class ApplicationTest {
         assertEquals ("Hello, World!", content);
     }
 
-    @Test public void no_query_parameter () throws IOException {
+    @Test(threadPoolSize = THREADS, invocationCount = EXECUTIONS)
+    public void no_query_parameter () throws IOException {
         HttpResponse response = get (ENDPOINT + "/db");
         String content = getContent (response);
 
@@ -57,35 +104,43 @@ public final class ApplicationTest {
         assertTrue (resultsMap.containsKey ("id") && resultsMap.containsKey ("randomNumber"));
     }
 
-    @Test public void empty_query_parameter () throws IOException {
+    @Test(threadPoolSize = THREADS, invocationCount = EXECUTIONS)
+    public void empty_query_parameter () throws IOException {
         checkDbRequest ("/query?queries", 1);
     }
 
-    @Test public void text_query_parameter () throws IOException {
+    @Test(threadPoolSize = THREADS, invocationCount = EXECUTIONS)
+    public void text_query_parameter () throws IOException {
         checkDbRequest ("/query?queries=text", 1);
     }
 
-    @Test public void zero_queries () throws IOException {
+    @Test(threadPoolSize = THREADS, invocationCount = EXECUTIONS)
+    public void zero_queries () throws IOException {
         checkDbRequest ("/query?queries=0", 1);
     }
 
-    @Test public void one_thousand_queries () throws IOException {
+    @Test(threadPoolSize = THREADS, invocationCount = EXECUTIONS)
+    public void one_thousand_queries () throws IOException {
         checkDbRequest ("/query?queries=1000", 500);
     }
 
-    @Test public void one_query () throws IOException {
+    @Test(threadPoolSize = THREADS, invocationCount = EXECUTIONS)
+    public void one_query () throws IOException {
         checkDbRequest ("/query?queries=1", 1);
     }
 
-    @Test public void ten_queries () throws IOException {
+    @Test(threadPoolSize = THREADS, invocationCount = EXECUTIONS)
+    public void ten_queries () throws IOException {
         checkDbRequest ("/query?queries=10", 10);
     }
 
-    @Test public void five_hundred_queries () throws IOException {
+    @Test(threadPoolSize = THREADS, invocationCount = EXECUTIONS)
+    public void five_hundred_queries () throws IOException {
         checkDbRequest ("/query?queries=500", 500);
     }
 
-    @Test public void fortunes () throws IOException {
+    @Test(threadPoolSize = THREADS, invocationCount = EXECUTIONS)
+    public void fortunes () throws IOException {
         HttpResponse response = get (ENDPOINT + "/fortune");
         String content = getContent (response);
         String contentType = response.getEntity ().getContentType ().getValue ();
@@ -94,10 +149,11 @@ public final class ApplicationTest {
         assertTrue (response.getFirstHeader ("Date") != null);
         assertTrue (content.contains ("&lt;script&gt;alert(&quot;This should not be displayed"));
         assertTrue (content.contains ("フレームワークのベンチマーク"));
-        assertEquals ("text/html; charset=utf-8", contentType);
+        assertEquals ("text/html; charset=utf-8", contentType.toLowerCase ());
     }
 
-    @Test public void no_updates_parameter () throws IOException {
+    @Test(threadPoolSize = THREADS, invocationCount = EXECUTIONS)
+    public void no_updates_parameter () throws IOException {
         HttpResponse response = get (ENDPOINT + "/update");
         String content = getContent (response);
 
@@ -106,31 +162,38 @@ public final class ApplicationTest {
         assertTrue (resultsMap.containsKey ("id") && resultsMap.containsKey ("randomNumber"));
     }
 
-    @Test public void empty_updates_parameter () throws IOException {
+    @Test(threadPoolSize = THREADS, invocationCount = EXECUTIONS)
+    public void empty_updates_parameter () throws IOException {
         checkDbRequest ("/update?queries", 1);
     }
 
-    @Test public void text_updates_parameter () throws IOException {
+    @Test(threadPoolSize = THREADS, invocationCount = EXECUTIONS)
+    public void text_updates_parameter () throws IOException {
         checkDbRequest ("/update?queries=text", 1);
     }
 
-    @Test public void zero_updates () throws IOException {
+    @Test(threadPoolSize = THREADS, invocationCount = EXECUTIONS)
+    public void zero_updates () throws IOException {
         checkDbRequest ("/update?queries=0", 1);
     }
 
-    @Test public void one_thousand_updates () throws IOException {
+    @Test(threadPoolSize = THREADS, invocationCount = EXECUTIONS)
+    public void one_thousand_updates () throws IOException {
         checkDbRequest ("/update?queries=1000", 500);
     }
 
-    @Test public void one_update () throws IOException {
+    @Test(threadPoolSize = THREADS, invocationCount = EXECUTIONS)
+    public void one_update () throws IOException {
         checkDbRequest ("/update?queries=1", 1);
     }
 
-    @Test public void ten_updates () throws IOException {
+    @Test(threadPoolSize = THREADS, invocationCount = EXECUTIONS)
+    public void ten_updates () throws IOException {
         checkDbRequest ("/update?queries=10", 10);
     }
 
-    @Test public void five_hundred_updates () throws IOException {
+    @Test(threadPoolSize = THREADS, invocationCount = EXECUTIONS)
+    public void five_hundred_updates () throws IOException {
         checkDbRequest ("/update?queries=500", 500);
     }