From dd1129b484fd8c7bc6f2fb978c9a0747aec9f468 Mon Sep 17 00:00:00 2001 From: hrj Date: Mon, 12 Apr 2021 19:01:57 +0530 Subject: [PATCH 01/16] added a debug captcha Signed-off-by: hrj --- src/main/scala/lc/captchas/DebugCaptcha.scala | 64 +++++++++++++++++++ src/main/scala/lc/core/captchaProviders.scala | 3 +- 2 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 src/main/scala/lc/captchas/DebugCaptcha.scala diff --git a/src/main/scala/lc/captchas/DebugCaptcha.scala b/src/main/scala/lc/captchas/DebugCaptcha.scala new file mode 100644 index 0000000..d0df653 --- /dev/null +++ b/src/main/scala/lc/captchas/DebugCaptcha.scala @@ -0,0 +1,64 @@ +package lc.captchas + +import javax.imageio.ImageIO +import java.awt.Color +import java.awt.Font +import java.awt.font.TextLayout +import java.awt.image.BufferedImage +import java.io.ByteArrayOutputStream +import java.util.Map +import java.util.List + +import lc.misc.HelperFunctions +import lc.captchas.interfaces.Challenge +import lc.captchas.interfaces.ChallengeProvider + +/** This captcha is only for debuggin purposes. It creates very simple captchas that are delibertely easy to solve with OCR engines */ +class DebugCaptcha extends ChallengeProvider { + + def getId(): String = { + "DebugCaptcha" + } + + def configure(config: String): Unit = { + // TODO: Add custom config + } + + def supportedParameters(): Map[String, List[String]] = { + Map.of( + "supportedLevels", List.of("debug"), + "supportedMedia", List.of("image/png"), + "supportedInputType", List.of("text") + ) + } + + def checkAnswer(secret: String, answer: String): Boolean = { + answer.toLowerCase().equals(secret) + } + + private def simpleText(text: String): Array[Byte] = { + val img = new BufferedImage(350, 100, BufferedImage.TYPE_INT_RGB) + val font = new Font("Arial", Font.ROMAN_BASELINE, 48) + val graphics2D = img.createGraphics() + val textLayout = new TextLayout(text, font, graphics2D.getFontRenderContext()) + HelperFunctions.setRenderingHints(graphics2D) + graphics2D.setPaint(Color.WHITE) + graphics2D.fillRect(0, 0, 350, 100) + graphics2D.setPaint(Color.BLACK) + textLayout.draw(graphics2D, 15, 50) + graphics2D.dispose() + val baos = new ByteArrayOutputStream() + try { + ImageIO.write(img, "png", baos) + } catch { + case e: Exception => + e.printStackTrace() + } + baos.toByteArray() + } + + def returnChallenge(): Challenge = { + val secret = HelperFunctions.randomString(6) + new Challenge(simpleText(secret), "image/png", secret.toLowerCase()) + } +} diff --git a/src/main/scala/lc/core/captchaProviders.scala b/src/main/scala/lc/core/captchaProviders.scala index d23f888..b36fed5 100644 --- a/src/main/scala/lc/core/captchaProviders.scala +++ b/src/main/scala/lc/core/captchaProviders.scala @@ -11,7 +11,8 @@ object CaptchaProviders { //"FontFunCaptcha" -> new FontFunCaptcha, "GifCaptcha" -> new GifCaptcha, "ShadowTextCaptcha" -> new ShadowTextCaptcha, - "RainDropsCaptcha" -> new RainDropsCP + "RainDropsCaptcha" -> new RainDropsCP, + "DebugCaptcha" -> new DebugCaptcha, //"LabelCaptcha" -> new LabelCaptcha ) From d9fefca8411a8531ffaa3ca3c1fe67a4863199e6 Mon Sep 17 00:00:00 2001 From: hrj Date: Mon, 12 Apr 2021 19:04:19 +0530 Subject: [PATCH 02/16] minor, spacing Signed-off-by: hrj --- src/main/scala/lc/core/captchaProviders.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/lc/core/captchaProviders.scala b/src/main/scala/lc/core/captchaProviders.scala index b36fed5..1174ade 100644 --- a/src/main/scala/lc/core/captchaProviders.scala +++ b/src/main/scala/lc/core/captchaProviders.scala @@ -57,7 +57,7 @@ object CaptchaProviders { def getProvider(param: Parameters): ChallengeProvider = { val providerConfig = filterProviderByParam(param).toList - if (providerConfig.length == 0) throw new NoSuchElementException(ErrorMessageEnum.NO_CAPTCHA.toString) + if (providerConfig.length == 0) throw new NoSuchElementException(ErrorMessageEnum.NO_CAPTCHA.toString) val randomIndex = getNextRandomInt(providerConfig.length) val providerIndex = providerConfig(randomIndex)._1 val selectedProvider = providers(providerIndex) From 3cfba7a08e1adc01710bb46c8f9234ebc67701b6 Mon Sep 17 00:00:00 2001 From: hrj Date: Mon, 12 Apr 2021 20:25:31 +0530 Subject: [PATCH 03/16] run functional test Signed-off-by: hrj --- tests/locustfile-functional.py | 68 ++++++++++++++++++++++++++++++++++ tests/run.sh | 10 ++++- 2 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 tests/locustfile-functional.py diff --git a/tests/locustfile-functional.py b/tests/locustfile-functional.py new file mode 100644 index 0000000..4effb4f --- /dev/null +++ b/tests/locustfile-functional.py @@ -0,0 +1,68 @@ +from locust import task, between, SequentialTaskSet +from locust.contrib.fasthttp import FastHttpUser +from locust import events +import json +import logging +import subprocess + +@events.quitting.add_listener +def _(environment, **kw): + if environment.stats.total.fail_ratio > 0.02: + logging.error("Test failed due to failure ratio > 2%") + environment.process_exit_code = 1 + elif environment.stats.total.avg_response_time > 300: + logging.error("Test failed due to average response time ratio > 300 ms") + environment.process_exit_code = 1 + elif environment.stats.total.get_response_time_percentile(0.95) > 800: + logging.error("Test failed due to 95th percentile response time > 800 ms") + environment.process_exit_code = 1 + else: + environment.process_exit_code = 0 + +class QuickStartUser(SequentialTaskSet): + wait_time = between(0.1,0.2) + + @task + def captcha(self): + # TODO: Iterate over parameters for a more comprehensive test + captcha_params = {"level":"debug","media":"image/png","input_type":"text"} + + resp = self.client.post(path="/v1/captcha", json=captcha_params, name="/captcha") + if resp.status_code != 200: + print("\nError on /captcha endpoint: ") + print(resp) + print(resp.text) + print("----------------END.CAPTCHA-------------------\n\n") + + uuid = resp.json().get("id") + + resp = self.client.get(path="/v1/media?id=%s" % uuid, name="/media", stream=True) + if resp.status_code != 200: + print("\nError on /media endpoint: ") + print(resp) + print(resp.text) + print("----------------END.MEDIA-------------------\n\n") + + media = resp.content + mediaFileName = "tests/test-%s.png" % uuid + with open(mediaFileName, "wb") as f: + f.write(media) + ocrResult = subprocess.Popen("gocr %s" % mediaFileName, shell=True, stdout=subprocess.PIPE) + ocrAnswer = ocrResult.stdout.readlines()[0].strip().decode() + + answerBody = {"answer": ocrAnswer,"id": uuid} + with self.client.post(path='/v1/answer', json=answerBody, name="/answer", catch_response=True) as resp: + if resp.status_code != 200: + print("\nError on /answer endpoint: ") + print(resp) + print(resp.text) + print("----------------END.ANSWER-------------------\n\n") + else: + if resp.json().get("result") != "True": + resp.failure("Answer was not accepted") + + +class User(FastHttpUser): + wait_time = between(0.1,0.2) + tasks = [QuickStartUser] + host = "http://localhost:8888" diff --git a/tests/run.sh b/tests/run.sh index 0d10e93..b00e7fa 100755 --- a/tests/run.sh +++ b/tests/run.sh @@ -10,6 +10,14 @@ sleep 4 locust --headless -u 300 -r 100 --run-time 4m --stop-timeout 30 -f tests/locustfile.py status=$? -kill $JAVA_PID +if [ $status != 0 ]; then + kill $JAVA_PID + exit $status +fi +echo Run functional test +locust --headless -u 1 -r 1 --run-time 1m --stop-timeout 30 -f tests/locustfile-functional.py +status=$? + +kill $JAVA_PID exit $status From a51defd2c7a6142f93ee34508b51603628d60a16 Mon Sep 17 00:00:00 2001 From: hrj Date: Mon, 12 Apr 2021 20:28:07 +0530 Subject: [PATCH 04/16] install gocr during CI Signed-off-by: hrj --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b48fcb0..edceef0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,4 +21,4 @@ jobs: - name: Run linter run: sbt "scalafixAll --check" - name: Run locust tests - run: ./tests/run.sh + run: apt-get update && apt-get -y upgrade && apt-get install -y gocr && ./tests/run.sh From 68dcfb1e49e2a4da6d1ca464e1c4085bd5e2016c Mon Sep 17 00:00:00 2001 From: hrj Date: Tue, 13 Apr 2021 07:55:45 +0530 Subject: [PATCH 05/16] CI: fix permission error Signed-off-by: hrj --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index edceef0..e3f7aa3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,4 +21,4 @@ jobs: - name: Run linter run: sbt "scalafixAll --check" - name: Run locust tests - run: apt-get update && apt-get -y upgrade && apt-get install -y gocr && ./tests/run.sh + run: sudo apt-get install -y gocr && ./tests/run.sh From c0ac570746a800a2d459ea0038a7d39380be0374 Mon Sep 17 00:00:00 2001 From: hrj Date: Tue, 13 Apr 2021 09:02:11 +0530 Subject: [PATCH 06/16] simplify locust file Signed-off-by: hrj --- tests/locustfile-functional.py | 48 ++++++++++++++++------------------ 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/tests/locustfile-functional.py b/tests/locustfile-functional.py index 4effb4f..7ba9639 100644 --- a/tests/locustfile-functional.py +++ b/tests/locustfile-functional.py @@ -24,43 +24,41 @@ class QuickStartUser(SequentialTaskSet): @task def captcha(self): - # TODO: Iterate over parameters for a more comprehensive test captcha_params = {"level":"debug","media":"image/png","input_type":"text"} - resp = self.client.post(path="/v1/captcha", json=captcha_params, name="/captcha") - if resp.status_code != 200: - print("\nError on /captcha endpoint: ") - print(resp) - print(resp.text) - print("----------------END.CAPTCHA-------------------\n\n") - - uuid = resp.json().get("id") + with self.client.post(path="/v1/captcha", json=captcha_params, name="/captcha", catch_response = True) as resp: + if resp.status_code != 200: + resp.failure("Status was not 200: " + resp.text) + captchaJson = resp.json() + uuid = captchaJson.get("id") + if not uuid: + resp.failure("uuid not returned on /captcha endpoint: " + resp.text) - resp = self.client.get(path="/v1/media?id=%s" % uuid, name="/media", stream=True) - if resp.status_code != 200: - print("\nError on /media endpoint: ") - print(resp) - print(resp.text) - print("----------------END.MEDIA-------------------\n\n") + with self.client.get(path="/v1/media?id=%s" % uuid, name="/media", stream=True, catch_response = True) as resp: + if resp.status_code != 200: + resp.failure("Status was not 200: " + resp.text) - media = resp.content - mediaFileName = "tests/test-%s.png" % uuid - with open(mediaFileName, "wb") as f: - f.write(media) - ocrResult = subprocess.Popen("gocr %s" % mediaFileName, shell=True, stdout=subprocess.PIPE) - ocrAnswer = ocrResult.stdout.readlines()[0].strip().decode() + media = resp.content + + ocrAnswer = self.solve(uuid, media) answerBody = {"answer": ocrAnswer,"id": uuid} with self.client.post(path='/v1/answer', json=answerBody, name="/answer", catch_response=True) as resp: if resp.status_code != 200: - print("\nError on /answer endpoint: ") - print(resp) - print(resp.text) - print("----------------END.ANSWER-------------------\n\n") + resp.failure("Status was not 200: " + resp.text) else: if resp.json().get("result") != "True": resp.failure("Answer was not accepted") + def solve(self, uuid, media): + mediaFileName = "tests/test-%s.png" % uuid + with open(mediaFileName, "wb") as f: + f.write(media) + ocrResult = subprocess.Popen("gocr %s" % mediaFileName, shell=True, stdout=subprocess.PIPE) + ocrAnswer = ocrResult.stdout.readlines()[0].strip().decode() + return ocrAnswer + + class User(FastHttpUser): wait_time = between(0.1,0.2) From 3845645f9a4b3e2c286054cc5b0e917f11645223 Mon Sep 17 00:00:00 2001 From: hrj Date: Tue, 13 Apr 2021 09:05:44 +0530 Subject: [PATCH 07/16] use debug config Signed-off-by: hrj --- tests/debug-config.json | 14 ++++++++++++++ tests/run.sh | 12 +++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 tests/debug-config.json diff --git a/tests/debug-config.json b/tests/debug-config.json new file mode 100644 index 0000000..ae04974 --- /dev/null +++ b/tests/debug-config.json @@ -0,0 +1,14 @@ +{ + "randomSeed" : 20, + "port" : 8888, + "captchaExpiryTimeLimit" : 5, + "throttle" : 10, + "threadDelay" : 2, + "captchas" : [ { + "name" : "DebugCaptcha", + "allowedLevels" : [ "debug" ], + "allowedMedia" : [ "image/png" ], + "allowedInputType" : [ "text" ], + "config" : { } + }] +} diff --git a/tests/run.sh b/tests/run.sh index b00e7fa..9a07c97 100755 --- a/tests/run.sh +++ b/tests/run.sh @@ -11,13 +11,23 @@ locust --headless -u 300 -r 100 --run-time 4m --stop-timeout 30 -f tests/locustf status=$? if [ $status != 0 ]; then - kill $JAVA_PID exit $status fi +kill $JAVA_PID +sleep 4 + echo Run functional test +cp data/config.json data/config.json.bak +cp tests/debug-config.json data/config.json + +java -jar target/scala-2.13/LibreCaptcha.jar & +JAVA_PID=$! +sleep 4 + locust --headless -u 1 -r 1 --run-time 1m --stop-timeout 30 -f tests/locustfile-functional.py status=$? +mv data/config.json.bak data/config.json kill $JAVA_PID exit $status From 328f0463790bae164943454999f458630bfce6b9 Mon Sep 17 00:00:00 2001 From: hrj Date: Tue, 13 Apr 2021 09:46:51 +0530 Subject: [PATCH 08/16] make locust output less verbose Signed-off-by: hrj --- tests/run.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/run.sh b/tests/run.sh index 9a07c97..0a81ad4 100755 --- a/tests/run.sh +++ b/tests/run.sh @@ -7,7 +7,7 @@ java -jar target/scala-2.13/LibreCaptcha.jar & JAVA_PID=$! sleep 4 -locust --headless -u 300 -r 100 --run-time 4m --stop-timeout 30 -f tests/locustfile.py +locust --only-summary --headless -u 300 -r 100 --run-time 4m --stop-timeout 30 -f tests/locustfile.py status=$? if [ $status != 0 ]; then @@ -25,7 +25,7 @@ java -jar target/scala-2.13/LibreCaptcha.jar & JAVA_PID=$! sleep 4 -locust --headless -u 1 -r 1 --run-time 1m --stop-timeout 30 -f tests/locustfile-functional.py +locust --only-summary --headless -u 1 -r 1 --run-time 1m --stop-timeout 30 -f tests/locustfile-functional.py status=$? mv data/config.json.bak data/config.json From 332bb2113b33784a3ec73a2511e0678d7b293562 Mon Sep 17 00:00:00 2001 From: hrj Date: Tue, 13 Apr 2021 11:48:07 +0530 Subject: [PATCH 09/16] minor, typos in comment Signed-off-by: hrj --- src/main/scala/lc/captchas/DebugCaptcha.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/lc/captchas/DebugCaptcha.scala b/src/main/scala/lc/captchas/DebugCaptcha.scala index d0df653..c581c05 100644 --- a/src/main/scala/lc/captchas/DebugCaptcha.scala +++ b/src/main/scala/lc/captchas/DebugCaptcha.scala @@ -13,7 +13,7 @@ import lc.misc.HelperFunctions import lc.captchas.interfaces.Challenge import lc.captchas.interfaces.ChallengeProvider -/** This captcha is only for debuggin purposes. It creates very simple captchas that are delibertely easy to solve with OCR engines */ +/** This captcha is only for debugging purposes. It creates very simple captchas that are deliberately easy to solve with OCR engines */ class DebugCaptcha extends ChallengeProvider { def getId(): String = { From 954399042ccff507e827b9e75a77f5694f90fb00 Mon Sep 17 00:00:00 2001 From: hrj Date: Tue, 13 Apr 2021 12:36:30 +0530 Subject: [PATCH 10/16] debug catpcha: only use alphabets Signed-off-by: hrj --- src/main/java/lc/misc/HelperFunctions.java | 14 +++++++++++--- src/main/scala/lc/captchas/DebugCaptcha.scala | 2 +- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/main/java/lc/misc/HelperFunctions.java b/src/main/java/lc/misc/HelperFunctions.java index f46d49e..446d903 100644 --- a/src/main/java/lc/misc/HelperFunctions.java +++ b/src/main/java/lc/misc/HelperFunctions.java @@ -11,9 +11,17 @@ public class HelperFunctions { RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); } - public static String randomString(int n) { - String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz23456789$#%@&?"; - StringBuilder stringBuilder = new StringBuilder(); + public static final String alphabets = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + public static final String numbers = "23456789"; + public static final String specialCharacters = "$#%@&?"; + public static final String allCharacters = alphabets + numbers + specialCharacters; + + public static String randomString(final int n) { + return randomString(n, allCharacters); + } + + public static String randomString(final int n, final String characters) { + final StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < n; i++) { int index = (int) (characters.length() * Math.random()); stringBuilder.append(characters.charAt(index)); diff --git a/src/main/scala/lc/captchas/DebugCaptcha.scala b/src/main/scala/lc/captchas/DebugCaptcha.scala index c581c05..fde6ab4 100644 --- a/src/main/scala/lc/captchas/DebugCaptcha.scala +++ b/src/main/scala/lc/captchas/DebugCaptcha.scala @@ -58,7 +58,7 @@ class DebugCaptcha extends ChallengeProvider { } def returnChallenge(): Challenge = { - val secret = HelperFunctions.randomString(6) + val secret = HelperFunctions.randomString(6, HelperFunctions.alphabets) new Challenge(simpleText(secret), "image/png", secret.toLowerCase()) } } From 41bdbc7fbf7a2d0fcc2de820f239c507f7f9a976 Mon Sep 17 00:00:00 2001 From: hrj Date: Tue, 13 Apr 2021 12:36:39 +0530 Subject: [PATCH 11/16] debug captcha: use a larger font Signed-off-by: hrj --- src/main/scala/lc/captchas/DebugCaptcha.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/lc/captchas/DebugCaptcha.scala b/src/main/scala/lc/captchas/DebugCaptcha.scala index fde6ab4..a2c4a62 100644 --- a/src/main/scala/lc/captchas/DebugCaptcha.scala +++ b/src/main/scala/lc/captchas/DebugCaptcha.scala @@ -38,7 +38,7 @@ class DebugCaptcha extends ChallengeProvider { private def simpleText(text: String): Array[Byte] = { val img = new BufferedImage(350, 100, BufferedImage.TYPE_INT_RGB) - val font = new Font("Arial", Font.ROMAN_BASELINE, 48) + val font = new Font("Arial", Font.ROMAN_BASELINE, 56) val graphics2D = img.createGraphics() val textLayout = new TextLayout(text, font, graphics2D.getFontRenderContext()) HelperFunctions.setRenderingHints(graphics2D) From b765399f68e5372bba141e04bb4f968790679bbf Mon Sep 17 00:00:00 2001 From: hrj Date: Tue, 13 Apr 2021 13:07:44 +0530 Subject: [PATCH 12/16] debug captcha: use safe alphabets only Signed-off-by: hrj --- src/main/java/lc/misc/HelperFunctions.java | 10 ++++++---- src/main/scala/lc/captchas/DebugCaptcha.scala | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/lc/misc/HelperFunctions.java b/src/main/java/lc/misc/HelperFunctions.java index 446d903..fa12fc8 100644 --- a/src/main/java/lc/misc/HelperFunctions.java +++ b/src/main/java/lc/misc/HelperFunctions.java @@ -11,13 +11,15 @@ public class HelperFunctions { RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); } - public static final String alphabets = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - public static final String numbers = "23456789"; + public static final String safeAlphabets = "ABCDEFGHJKMNOPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; + public static final String allAlphabets = safeAlphabets + "ILl"; + public static final String safeNumbers = "23456789"; + public static final String allNumbers = safeNumbers + "1"; public static final String specialCharacters = "$#%@&?"; - public static final String allCharacters = alphabets + numbers + specialCharacters; + public static final String safeCharacters = safeAlphabets + safeNumbers + specialCharacters; public static String randomString(final int n) { - return randomString(n, allCharacters); + return randomString(n, safeCharacters); } public static String randomString(final int n, final String characters) { diff --git a/src/main/scala/lc/captchas/DebugCaptcha.scala b/src/main/scala/lc/captchas/DebugCaptcha.scala index a2c4a62..084f1e1 100644 --- a/src/main/scala/lc/captchas/DebugCaptcha.scala +++ b/src/main/scala/lc/captchas/DebugCaptcha.scala @@ -58,7 +58,7 @@ class DebugCaptcha extends ChallengeProvider { } def returnChallenge(): Challenge = { - val secret = HelperFunctions.randomString(6, HelperFunctions.alphabets) + val secret = HelperFunctions.randomString(6, HelperFunctions.safeAlphabets) new Challenge(simpleText(secret), "image/png", secret.toLowerCase()) } } From 1ff4a30da74de0a396c2dfce00251c6b38b78b6f Mon Sep 17 00:00:00 2001 From: hrj Date: Tue, 13 Apr 2021 13:42:34 +0530 Subject: [PATCH 13/16] use tesseract instead of gocr Signed-off-by: hrj --- .github/workflows/ci.yml | 2 +- tests/locustfile-functional.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e3f7aa3..8a5d80d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,4 +21,4 @@ jobs: - name: Run linter run: sbt "scalafixAll --check" - name: Run locust tests - run: sudo apt-get install -y gocr && ./tests/run.sh + run: sudo apt-get install -y tesseract-ocr && ./tests/run.sh diff --git a/tests/locustfile-functional.py b/tests/locustfile-functional.py index 7ba9639..21cfb92 100644 --- a/tests/locustfile-functional.py +++ b/tests/locustfile-functional.py @@ -54,7 +54,8 @@ class QuickStartUser(SequentialTaskSet): mediaFileName = "tests/test-%s.png" % uuid with open(mediaFileName, "wb") as f: f.write(media) - ocrResult = subprocess.Popen("gocr %s" % mediaFileName, shell=True, stdout=subprocess.PIPE) + #ocrResult = subprocess.Popen("gocr %s" % mediaFileName, shell=True, stdout=subprocess.PIPE) + ocrResult = subprocess.Popen("tesseract %s stdout -l eng" % mediaFileName, shell=True, stdout=subprocess.PIPE) ocrAnswer = ocrResult.stdout.readlines()[0].strip().decode() return ocrAnswer From 96b5808628fa199d09e6e09a96c8b3f9c1e70641 Mon Sep 17 00:00:00 2001 From: hrj Date: Tue, 13 Apr 2021 14:01:25 +0530 Subject: [PATCH 14/16] correctly parse parameter values from config Signed-off-by: hrj --- src/main/scala/lc/core/config.scala | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/src/main/scala/lc/core/config.scala b/src/main/scala/lc/core/config.scala index 09dbc20..233108f 100644 --- a/src/main/scala/lc/core/config.scala +++ b/src/main/scala/lc/core/config.scala @@ -44,25 +44,9 @@ object Config { case JField("config", JObject(config)) => ("config", JString(config.toString)) } val captchaConfig: List[CaptchaConfig] = captchaConfigTransform.extract[List[CaptchaConfig]] - val allowedLevels: Set[String] = getAllValues(configJson, ParametersEnum.ALLOWEDLEVELS.toString) - val allowedMedia: Set[String] = getAllValues(configJson, ParametersEnum.ALLOWEDMEDIA.toString) - val allowedInputType: Set[String] = getAllValues(configJson, ParametersEnum.ALLOWEDINPUTTYPE.toString) - - private def getAllValues(config: JValue, param: String): Set[String] = { - val configValues = (config \\ param) - val result = for { - JObject(child) <- configValues - JField(param) <- child - } yield (param) - - var valueSet = Set[String]() - for (valueList <- result) { - for (value <- valueList._2.children) { - valueSet += value.values.toString - } - } - valueSet - } + val allowedLevels: Set[String] = captchaConfig.flatMap(_.allowedLevels).toSet + val allowedMedia: Set[String] = captchaConfig.flatMap(_.allowedMedia).toSet + val allowedInputType: Set[String] = captchaConfig.flatMap(_.allowedInputType).toSet private def getDefaultConfig(): String = { val defaultConfigMap = From 1d746f7655bc238c0f39c9c99ce41d4d35619a87 Mon Sep 17 00:00:00 2001 From: hrj Date: Tue, 13 Apr 2021 14:26:50 +0530 Subject: [PATCH 15/16] functional test: reduce failure criteria Signed-off-by: hrj --- tests/locustfile-functional.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/tests/locustfile-functional.py b/tests/locustfile-functional.py index 21cfb92..c68d195 100644 --- a/tests/locustfile-functional.py +++ b/tests/locustfile-functional.py @@ -7,14 +7,12 @@ import subprocess @events.quitting.add_listener def _(environment, **kw): - if environment.stats.total.fail_ratio > 0.02: - logging.error("Test failed due to failure ratio > 2%") + totalStats = environment.stats.total + if totalStats.fail_ratio > 0.20: + logging.error("Test failed due to failure ratio " + totalStats.fail_ratio + " > 20%") environment.process_exit_code = 1 - elif environment.stats.total.avg_response_time > 300: - logging.error("Test failed due to average response time ratio > 300 ms") - environment.process_exit_code = 1 - elif environment.stats.total.get_response_time_percentile(0.95) > 800: - logging.error("Test failed due to 95th percentile response time > 800 ms") + elif totalStats.get_response_time_percentile(0.80) > 800: + logging.error("Test failed due to 80th percentile response time > 800 ms") environment.process_exit_code = 1 else: environment.process_exit_code = 0 From caf3669bd907be7257e56704ee23c6f675d521df Mon Sep 17 00:00:00 2001 From: hrj Date: Tue, 13 Apr 2021 14:28:14 +0530 Subject: [PATCH 16/16] functional tests: show failed answers Signed-off-by: hrj --- tests/locustfile-functional.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/locustfile-functional.py b/tests/locustfile-functional.py index c68d195..5034e43 100644 --- a/tests/locustfile-functional.py +++ b/tests/locustfile-functional.py @@ -46,7 +46,7 @@ class QuickStartUser(SequentialTaskSet): resp.failure("Status was not 200: " + resp.text) else: if resp.json().get("result") != "True": - resp.failure("Answer was not accepted") + resp.failure("Answer was not accepted: " + ocrAnswer) def solve(self, uuid, media): mediaFileName = "tests/test-%s.png" % uuid