summaryrefslogtreecommitdiffstats
path: root/toolkit/components/contentanalysis/tests
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/contentanalysis/tests')
-rw-r--r--toolkit/components/contentanalysis/tests/gtest/TestContentAnalysis.cpp132
-rw-r--r--toolkit/components/contentanalysis/tests/gtest/TestContentAnalysis.h24
-rw-r--r--toolkit/components/contentanalysis/tests/gtest/TestContentAnalysisMisbehaving.cpp416
-rw-r--r--toolkit/components/contentanalysis/tests/gtest/TestContentAnalysisUtils.cpp75
-rw-r--r--toolkit/components/contentanalysis/tests/gtest/agent/moz.build40
-rw-r--r--toolkit/components/contentanalysis/tests/gtest/allowedFile.txt1
-rw-r--r--toolkit/components/contentanalysis/tests/gtest/blockedFile.txt1
-rw-r--r--toolkit/components/contentanalysis/tests/gtest/moz.build23
8 files changed, 712 insertions, 0 deletions
diff --git a/toolkit/components/contentanalysis/tests/gtest/TestContentAnalysis.cpp b/toolkit/components/contentanalysis/tests/gtest/TestContentAnalysis.cpp
new file mode 100644
index 0000000000..1cf6d8fc22
--- /dev/null
+++ b/toolkit/components/contentanalysis/tests/gtest/TestContentAnalysis.cpp
@@ -0,0 +1,132 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+#include "gtest/gtest.h"
+#include "mozilla/ArrayUtils.h"
+#include "mozilla/Assertions.h"
+#include "mozilla/CmdLineAndEnvUtils.h"
+#include "content_analysis/sdk/analysis_client.h"
+#include "TestContentAnalysis.h"
+#include <processenv.h>
+#include <synchapi.h>
+
+using namespace content_analysis::sdk;
+
+MozAgentInfo LaunchAgentNormal(const wchar_t* aToBlock) {
+ nsString cmdLineArguments;
+ if (aToBlock && aToBlock[0] != 0) {
+ cmdLineArguments.Append(L" --toblock=.*");
+ cmdLineArguments.Append(aToBlock);
+ cmdLineArguments.Append(L".*");
+ }
+ cmdLineArguments.Append(L" --user");
+ cmdLineArguments.Append(L" --path=");
+ nsString pipeName;
+ GeneratePipeName(L"contentanalysissdk-gtest-", pipeName);
+ cmdLineArguments.Append(pipeName);
+ MozAgentInfo agentInfo;
+ LaunchAgentWithCommandLineArguments(cmdLineArguments, pipeName, agentInfo);
+ return agentInfo;
+}
+
+TEST(ContentAnalysis, TextShouldNotBeBlocked)
+{
+ auto MozAgentInfo = LaunchAgentNormal(L"block");
+ // Exit the test early if the process failed to launch
+ ASSERT_NE(MozAgentInfo.processInfo.dwProcessId, 0UL);
+ ASSERT_NE(nullptr, MozAgentInfo.client.get());
+
+ ContentAnalysisRequest request;
+ request.set_request_token("request token");
+ request.set_text_content("should succeed");
+ ContentAnalysisResponse response;
+ ASSERT_EQ(0, MozAgentInfo.client->Send(request, &response));
+ ASSERT_STREQ("request token", response.request_token().c_str());
+ ASSERT_EQ(1, response.results().size());
+ ASSERT_EQ(ContentAnalysisResponse_Result_Status_SUCCESS,
+ response.results().Get(0).status());
+ ASSERT_EQ(0, response.results().Get(0).triggered_rules_size());
+
+ BOOL terminateResult =
+ ::TerminateProcess(MozAgentInfo.processInfo.hProcess, 0);
+ ASSERT_NE(FALSE, terminateResult)
+ << "Failed to terminate content_analysis_sdk_agent process";
+}
+
+TEST(ContentAnalysis, TextShouldBeBlocked)
+{
+ auto MozAgentInfo = LaunchAgentNormal(L"block");
+ // Exit the test early if the process failed to launch
+ ASSERT_NE(MozAgentInfo.processInfo.dwProcessId, 0UL);
+ ASSERT_NE(nullptr, MozAgentInfo.client.get());
+
+ ContentAnalysisRequest request;
+ request.set_request_token("request token");
+ request.set_text_content("should be blocked");
+ ContentAnalysisResponse response;
+ ASSERT_EQ(0, MozAgentInfo.client->Send(request, &response));
+ ASSERT_STREQ("request token", response.request_token().c_str());
+ ASSERT_EQ(1, response.results().size());
+ ASSERT_EQ(ContentAnalysisResponse_Result_Status_SUCCESS,
+ response.results().Get(0).status());
+ ASSERT_EQ(1, response.results().Get(0).triggered_rules_size());
+ ASSERT_EQ(ContentAnalysisResponse_Result_TriggeredRule_Action_BLOCK,
+ response.results().Get(0).triggered_rules(0).action());
+
+ BOOL terminateResult =
+ ::TerminateProcess(MozAgentInfo.processInfo.hProcess, 0);
+ ASSERT_NE(FALSE, terminateResult)
+ << "Failed to terminate content_analysis_sdk_agent process";
+}
+
+TEST(ContentAnalysis, FileShouldNotBeBlocked)
+{
+ auto MozAgentInfo = LaunchAgentNormal(L"block");
+ // Exit the test early if the process failed to launch
+ ASSERT_NE(MozAgentInfo.processInfo.dwProcessId, 0UL);
+ ASSERT_NE(nullptr, MozAgentInfo.client.get());
+
+ ContentAnalysisRequest request;
+ request.set_request_token("request token");
+ request.set_file_path("..\\..\\_tests\\gtest\\allowedFile.txt");
+ ContentAnalysisResponse response;
+ ASSERT_EQ(0, MozAgentInfo.client->Send(request, &response));
+ ASSERT_STREQ("request token", response.request_token().c_str());
+ ASSERT_EQ(1, response.results().size());
+ ASSERT_EQ(ContentAnalysisResponse_Result_Status_SUCCESS,
+ response.results().Get(0).status());
+ ASSERT_EQ(0, response.results().Get(0).triggered_rules_size());
+
+ BOOL terminateResult =
+ ::TerminateProcess(MozAgentInfo.processInfo.hProcess, 0);
+ ASSERT_NE(FALSE, terminateResult)
+ << "Failed to terminate content_analysis_sdk_agent process";
+}
+
+TEST(ContentAnalysis, FileShouldBeBlocked)
+{
+ auto MozAgentInfo = LaunchAgentNormal(L"block");
+ // Exit the test early if the process failed to launch
+ ASSERT_NE(MozAgentInfo.processInfo.dwProcessId, 0UL);
+ ASSERT_NE(nullptr, MozAgentInfo.client.get());
+
+ ContentAnalysisRequest request;
+ request.set_request_token("request token");
+ request.set_file_path("..\\..\\_tests\\gtest\\blockedFile.txt");
+ ContentAnalysisResponse response;
+ ASSERT_EQ(0, MozAgentInfo.client->Send(request, &response));
+ ASSERT_STREQ("request token", response.request_token().c_str());
+ ASSERT_EQ(1, response.results().size());
+ ASSERT_EQ(ContentAnalysisResponse_Result_Status_SUCCESS,
+ response.results().Get(0).status());
+ ASSERT_EQ(1, response.results().Get(0).triggered_rules_size());
+ ASSERT_EQ(ContentAnalysisResponse_Result_TriggeredRule_Action_BLOCK,
+ response.results().Get(0).triggered_rules(0).action());
+
+ BOOL terminateResult =
+ ::TerminateProcess(MozAgentInfo.processInfo.hProcess, 0);
+ ASSERT_NE(FALSE, terminateResult)
+ << "Failed to terminate content_analysis_sdk_agent process";
+}
diff --git a/toolkit/components/contentanalysis/tests/gtest/TestContentAnalysis.h b/toolkit/components/contentanalysis/tests/gtest/TestContentAnalysis.h
new file mode 100644
index 0000000000..9e31036262
--- /dev/null
+++ b/toolkit/components/contentanalysis/tests/gtest/TestContentAnalysis.h
@@ -0,0 +1,24 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#ifndef mozilla_testcontentanalysis_h
+#define mozilla_testcontentanalysis_h
+
+#include <processthreadsapi.h>
+
+#include "content_analysis/sdk/analysis_client.h"
+#include "gtest/gtest.h"
+#include "nsString.h"
+
+struct MozAgentInfo {
+ PROCESS_INFORMATION processInfo;
+ std::unique_ptr<content_analysis::sdk::Client> client;
+};
+
+void GeneratePipeName(const wchar_t* prefix, nsString& pipeName);
+void LaunchAgentWithCommandLineArguments(const nsString& cmdLineArguments,
+ const nsString& pipeName,
+ MozAgentInfo& agentInfo);
+#endif
diff --git a/toolkit/components/contentanalysis/tests/gtest/TestContentAnalysisMisbehaving.cpp b/toolkit/components/contentanalysis/tests/gtest/TestContentAnalysisMisbehaving.cpp
new file mode 100644
index 0000000000..0b005e1f6c
--- /dev/null
+++ b/toolkit/components/contentanalysis/tests/gtest/TestContentAnalysisMisbehaving.cpp
@@ -0,0 +1,416 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+#include "gtest/gtest.h"
+#include "mozilla/ArrayUtils.h"
+#include "mozilla/Assertions.h"
+#include "mozilla/CmdLineAndEnvUtils.h"
+#include "content_analysis/sdk/analysis_client.h"
+#include "TestContentAnalysis.h"
+#include <processenv.h>
+#include <synchapi.h>
+#include <windows.h>
+
+using namespace content_analysis::sdk;
+
+namespace {
+MozAgentInfo LaunchAgentMisbehaving(const wchar_t* mode) {
+ nsString cmdLineArguments;
+ cmdLineArguments.Append(L" --misbehave=");
+ cmdLineArguments.Append(mode);
+ cmdLineArguments.Append(L" --user");
+ cmdLineArguments.Append(L" --path=");
+ nsString pipeName;
+ GeneratePipeName(L"contentanalysissdk-gtest-", pipeName);
+ cmdLineArguments.Append(pipeName);
+ MozAgentInfo agentInfo;
+ LaunchAgentWithCommandLineArguments(cmdLineArguments, pipeName, agentInfo);
+ return agentInfo;
+}
+} // namespace
+
+// Disabled for now
+/*TEST(ContentAnalysisMisbehaving, LargeResponse)
+{
+ auto MozAgentInfo = LaunchAgentMisbehaving(L"largeResponse");
+ // Exit the test early if the process failed to launch
+ ASSERT_NE(MozAgentInfo.processInfo.dwProcessId, 0UL);
+ ASSERT_NE(nullptr, MozAgentInfo.client.get());
+
+ ContentAnalysisRequest request;
+ request.set_request_token("request token");
+ request.set_text_content("unused");
+ ContentAnalysisResponse response;
+ ASSERT_EQ(0, MozAgentInfo.client->Send(request, &response));
+ ASSERT_STREQ("request token", response.request_token().c_str());
+ ASSERT_EQ(1001, response.results().size());
+
+ BOOL terminateResult = ::TerminateProcess(MozAgentInfo.processInfo.hProcess,
+0); ASSERT_NE(FALSE, terminateResult)
+ << "Failed to terminate content_analysis_sdk_agent process";
+}*/
+
+TEST(ContentAnalysisMisbehaving, InvalidUtf8StringStartByteIsContinuationByte)
+{
+ auto MozAgentInfo =
+ LaunchAgentMisbehaving(L"invalidUtf8StringStartByteIsContinuationByte");
+ // Exit the test early if the process failed to launch
+ ASSERT_NE(MozAgentInfo.processInfo.dwProcessId, 0UL);
+ ASSERT_NE(nullptr, MozAgentInfo.client.get());
+
+ ContentAnalysisRequest request;
+ request.set_request_token("request token");
+ request.set_text_content("unused");
+ ContentAnalysisResponse response;
+ ASSERT_EQ(0, MozAgentInfo.client->Send(request, &response));
+ // The protobuf spec says that strings must be valid UTF-8. So it's OK if
+ // this gets mangled, just want to make sure it doesn't cause a crash
+ // or invalid memory access or something.
+ ASSERT_STREQ("\x80\x41\x41\x41", response.request_token().c_str());
+
+ BOOL terminateResult =
+ ::TerminateProcess(MozAgentInfo.processInfo.hProcess, 0);
+ ASSERT_NE(FALSE, terminateResult)
+ << "Failed to terminate content_analysis_sdk_agent process";
+}
+
+TEST(ContentAnalysisMisbehaving,
+ InvalidUtf8StringEndsInMiddleOfMultibyteSequence)
+{
+ auto MozAgentInfo = LaunchAgentMisbehaving(
+ L"invalidUtf8StringEndsInMiddleOfMultibyteSequence");
+ // Exit the test early if the process failed to launch
+ ASSERT_NE(MozAgentInfo.processInfo.dwProcessId, 0UL);
+ ASSERT_NE(nullptr, MozAgentInfo.client.get());
+
+ ContentAnalysisRequest request;
+ request.set_request_token("request token");
+ request.set_text_content("unused");
+ ContentAnalysisResponse response;
+ ASSERT_EQ(0, MozAgentInfo.client->Send(request, &response));
+ // The protobuf spec says that strings must be valid UTF-8. So it's OK if
+ // this gets mangled, just want to make sure it doesn't cause a crash
+ // or invalid memory access or something.
+ ASSERT_STREQ("\x41\xf0\x90\x8d", response.request_token().c_str());
+
+ BOOL terminateResult =
+ ::TerminateProcess(MozAgentInfo.processInfo.hProcess, 0);
+ ASSERT_NE(FALSE, terminateResult)
+ << "Failed to terminate content_analysis_sdk_agent process";
+}
+
+TEST(ContentAnalysisMisbehaving, InvalidUtf8StringMultibyteSequenceTooShort)
+{
+ auto MozAgentInfo =
+ LaunchAgentMisbehaving(L"invalidUtf8StringMultibyteSequenceTooShort");
+ // Exit the test early if the process failed to launch
+ ASSERT_NE(MozAgentInfo.processInfo.dwProcessId, 0UL);
+ ASSERT_NE(nullptr, MozAgentInfo.client.get());
+
+ ContentAnalysisRequest request;
+ request.set_request_token("request token");
+ request.set_text_content("unused");
+ ContentAnalysisResponse response;
+ ASSERT_EQ(0, MozAgentInfo.client->Send(request, &response));
+ // The protobuf spec says that strings must be valid UTF-8. So it's OK if
+ // this gets mangled, just want to make sure it doesn't cause a crash
+ // or invalid memory access or something.
+ ASSERT_STREQ("\xf0\x90\x8d\x41", response.request_token().c_str());
+
+ BOOL terminateResult =
+ ::TerminateProcess(MozAgentInfo.processInfo.hProcess, 0);
+ ASSERT_NE(FALSE, terminateResult)
+ << "Failed to terminate content_analysis_sdk_agent process";
+}
+
+TEST(ContentAnalysisMisbehaving, InvalidUtf8StringDecodesToInvalidCodePoint)
+{
+ auto MozAgentInfo =
+ LaunchAgentMisbehaving(L"invalidUtf8StringDecodesToInvalidCodePoint");
+ // Exit the test early if the process failed to launch
+ ASSERT_NE(MozAgentInfo.processInfo.dwProcessId, 0UL);
+ ASSERT_NE(nullptr, MozAgentInfo.client.get());
+
+ ContentAnalysisRequest request;
+ request.set_request_token("request token");
+ request.set_text_content("unused");
+ ContentAnalysisResponse response;
+ ASSERT_EQ(0, MozAgentInfo.client->Send(request, &response));
+ // The protobuf spec says that strings must be valid UTF-8. So it's OK if
+ // this gets mangled, just want to make sure it doesn't cause a crash
+ // or invalid memory access or something.
+ ASSERT_STREQ("\xf7\xbf\xbf\xbf", response.request_token().c_str());
+
+ BOOL terminateResult =
+ ::TerminateProcess(MozAgentInfo.processInfo.hProcess, 0);
+ ASSERT_NE(FALSE, terminateResult)
+ << "Failed to terminate content_analysis_sdk_agent process";
+}
+
+TEST(ContentAnalysisMisbehaving, InvalidUtf8StringOverlongEncoding)
+{
+ auto MozAgentInfo =
+ LaunchAgentMisbehaving(L"invalidUtf8StringOverlongEncoding");
+ // Exit the test early if the process failed to launch
+ ASSERT_NE(MozAgentInfo.processInfo.dwProcessId, 0UL);
+ ASSERT_NE(nullptr, MozAgentInfo.client.get());
+
+ ContentAnalysisRequest request;
+ request.set_request_token("request token");
+ request.set_text_content("unused");
+ ContentAnalysisResponse response;
+ ASSERT_EQ(0, MozAgentInfo.client->Send(request, &response));
+ // The protobuf spec says that strings must be valid UTF-8. So it's OK if
+ // this gets mangled, just want to make sure it doesn't cause a crash
+ // or invalid memory access or something.
+ ASSERT_STREQ("\xf0\x82\x82\xac", response.request_token().c_str());
+
+ BOOL terminateResult =
+ ::TerminateProcess(MozAgentInfo.processInfo.hProcess, 0);
+ ASSERT_NE(FALSE, terminateResult)
+ << "Failed to terminate content_analysis_sdk_agent process";
+}
+
+TEST(ContentAnalysisMisbehaving, StringWithEmbeddedNull)
+{
+ auto MozAgentInfo = LaunchAgentMisbehaving(L"stringWithEmbeddedNull");
+ // Exit the test early if the process failed to launch
+ ASSERT_NE(MozAgentInfo.processInfo.dwProcessId, 0UL);
+ ASSERT_NE(nullptr, MozAgentInfo.client.get());
+
+ ContentAnalysisRequest request;
+ request.set_request_token("request token");
+ request.set_text_content("unused");
+ ContentAnalysisResponse response;
+ ASSERT_EQ(0, MozAgentInfo.client->Send(request, &response));
+ std::string expected("\x41\x00\x41");
+ ASSERT_EQ(expected, response.request_token());
+
+ BOOL terminateResult =
+ ::TerminateProcess(MozAgentInfo.processInfo.hProcess, 0);
+ ASSERT_NE(FALSE, terminateResult)
+ << "Failed to terminate content_analysis_sdk_agent process";
+}
+
+TEST(ContentAnalysisMisbehaving, ZeroResults)
+{
+ auto MozAgentInfo = LaunchAgentMisbehaving(L"zeroResults");
+ // Exit the test early if the process failed to launch
+ ASSERT_NE(MozAgentInfo.processInfo.dwProcessId, 0UL);
+ ASSERT_NE(nullptr, MozAgentInfo.client.get());
+
+ ContentAnalysisRequest request;
+ request.set_request_token("request token");
+ request.set_text_content("unused");
+ ContentAnalysisResponse response;
+ ASSERT_EQ(0, MozAgentInfo.client->Send(request, &response));
+ ASSERT_EQ(0, response.results().size());
+
+ BOOL terminateResult =
+ ::TerminateProcess(MozAgentInfo.processInfo.hProcess, 0);
+ ASSERT_NE(FALSE, terminateResult)
+ << "Failed to terminate content_analysis_sdk_agent process";
+}
+
+TEST(ContentAnalysisMisbehaving, ResultWithInvalidStatus)
+{
+ auto MozAgentInfo = LaunchAgentMisbehaving(L"resultWithInvalidStatus");
+ // Exit the test early if the process failed to launch
+ ASSERT_NE(MozAgentInfo.processInfo.dwProcessId, 0UL);
+ ASSERT_NE(nullptr, MozAgentInfo.client.get());
+
+ ContentAnalysisRequest request;
+ request.set_request_token("request token");
+ request.set_text_content("unused");
+ ContentAnalysisResponse response;
+ ASSERT_EQ(0, MozAgentInfo.client->Send(request, &response));
+ ASSERT_EQ(1, response.results().size());
+ // protobuf will fail to read this because it's an invalid value.
+ // (and leave status at its default value of 0)
+ // just make sure we can get the value without throwing
+ ASSERT_GE(static_cast<int>(response.results(0).status()), 0);
+
+ BOOL terminateResult =
+ ::TerminateProcess(MozAgentInfo.processInfo.hProcess, 0);
+ ASSERT_NE(FALSE, terminateResult)
+ << "Failed to terminate content_analysis_sdk_agent process";
+}
+
+TEST(ContentAnalysisMisbehaving, MessageTruncatedInMiddleOfString)
+{
+ auto MozAgentInfo =
+ LaunchAgentMisbehaving(L"messageTruncatedInMiddleOfString");
+ // Exit the test early if the process failed to launch
+ ASSERT_NE(MozAgentInfo.processInfo.dwProcessId, 0UL);
+ ASSERT_NE(nullptr, MozAgentInfo.client.get());
+
+ ContentAnalysisRequest request;
+ request.set_request_token("request token");
+ ContentAnalysisResponse response;
+ // The response is an invalid serialization of protobuf, so this should fail
+ ASSERT_EQ(-1, MozAgentInfo.client->Send(request, &response));
+
+ BOOL terminateResult =
+ ::TerminateProcess(MozAgentInfo.processInfo.hProcess, 0);
+ ASSERT_NE(FALSE, terminateResult)
+ << "Failed to terminate content_analysis_sdk_agent process";
+}
+
+TEST(ContentAnalysisMisbehaving, MessageWithInvalidWireType)
+{
+ auto MozAgentInfo = LaunchAgentMisbehaving(L"messageWithInvalidWireType");
+ // Exit the test early if the process failed to launch
+ ASSERT_NE(MozAgentInfo.processInfo.dwProcessId, 0UL);
+ ASSERT_NE(nullptr, MozAgentInfo.client.get());
+
+ ContentAnalysisRequest request;
+ request.set_request_token("request token");
+ ContentAnalysisResponse response;
+ // The response is an invalid serialization of protobuf, so this should fail
+ ASSERT_EQ(-1, MozAgentInfo.client->Send(request, &response));
+
+ BOOL terminateResult =
+ ::TerminateProcess(MozAgentInfo.processInfo.hProcess, 0);
+ ASSERT_NE(FALSE, terminateResult)
+ << "Failed to terminate content_analysis_sdk_agent process";
+}
+
+TEST(ContentAnalysisMisbehaving, MessageWithUnusedFieldNumber)
+{
+ auto MozAgentInfo = LaunchAgentMisbehaving(L"messageWithUnusedFieldNumber");
+ // Exit the test early if the process failed to launch
+ ASSERT_NE(MozAgentInfo.processInfo.dwProcessId, 0UL);
+ ASSERT_NE(nullptr, MozAgentInfo.client.get());
+
+ ContentAnalysisRequest request;
+ request.set_request_token("request token");
+ ContentAnalysisResponse response;
+ ASSERT_EQ(0, MozAgentInfo.client->Send(request, &response));
+ // protobuf will read the value and store it in an unused section
+ // just make sure we can get a value without throwing
+ ASSERT_STREQ("", response.request_token().c_str());
+
+ BOOL terminateResult =
+ ::TerminateProcess(MozAgentInfo.processInfo.hProcess, 0);
+ ASSERT_NE(FALSE, terminateResult)
+ << "Failed to terminate content_analysis_sdk_agent process";
+}
+
+TEST(ContentAnalysisMisbehaving, MessageWithWrongStringWireType)
+{
+ auto MozAgentInfo = LaunchAgentMisbehaving(L"messageWithWrongStringWireType");
+ // Exit the test early if the process failed to launch
+ ASSERT_NE(MozAgentInfo.processInfo.dwProcessId, 0UL);
+ ASSERT_NE(nullptr, MozAgentInfo.client.get());
+
+ ContentAnalysisRequest request;
+ request.set_request_token("request token");
+ ContentAnalysisResponse response;
+ // The response is an invalid serialization of protobuf, so this should fail
+ ASSERT_EQ(-1, MozAgentInfo.client->Send(request, &response));
+
+ BOOL terminateResult =
+ ::TerminateProcess(MozAgentInfo.processInfo.hProcess, 0);
+ ASSERT_NE(FALSE, terminateResult)
+ << "Failed to terminate content_analysis_sdk_agent process";
+}
+
+TEST(ContentAnalysisMisbehaving, MessageWithZeroTag)
+{
+ auto MozAgentInfo = LaunchAgentMisbehaving(L"messageWithZeroTag");
+ // Exit the test early if the process failed to launch
+ ASSERT_NE(MozAgentInfo.processInfo.dwProcessId, 0UL);
+ ASSERT_NE(nullptr, MozAgentInfo.client.get());
+
+ ContentAnalysisRequest request;
+ request.set_request_token("request token");
+ ContentAnalysisResponse response;
+ // The response is an invalid serialization of protobuf, so this should fail
+ ASSERT_EQ(-1, MozAgentInfo.client->Send(request, &response));
+
+ BOOL terminateResult =
+ ::TerminateProcess(MozAgentInfo.processInfo.hProcess, 0);
+ ASSERT_NE(FALSE, terminateResult)
+ << "Failed to terminate content_analysis_sdk_agent process";
+}
+
+TEST(ContentAnalysisMisbehaving, MessageWithZeroFieldButNonzeroWireType)
+{
+ auto MozAgentInfo =
+ LaunchAgentMisbehaving(L"messageWithZeroFieldButNonzeroWireType");
+ // Exit the test early if the process failed to launch
+ ASSERT_NE(MozAgentInfo.processInfo.dwProcessId, 0UL);
+ ASSERT_NE(nullptr, MozAgentInfo.client.get());
+
+ ContentAnalysisRequest request;
+ request.set_request_token("request token");
+ ContentAnalysisResponse response;
+ // The response is an invalid serialization of protobuf, so this should fail
+ ASSERT_EQ(-1, MozAgentInfo.client->Send(request, &response));
+
+ BOOL terminateResult =
+ ::TerminateProcess(MozAgentInfo.processInfo.hProcess, 0);
+ ASSERT_NE(FALSE, terminateResult)
+ << "Failed to terminate content_analysis_sdk_agent process";
+}
+
+TEST(ContentAnalysisMisbehaving, MessageWithGroupEnd)
+{
+ auto MozAgentInfo =
+ LaunchAgentMisbehaving(L"messageWithZeroFieldButNonzeroWireType");
+ // Exit the test early if the process failed to launch
+ ASSERT_NE(MozAgentInfo.processInfo.dwProcessId, 0UL);
+ ASSERT_NE(nullptr, MozAgentInfo.client.get());
+
+ ContentAnalysisRequest request;
+ request.set_request_token("request token");
+ ContentAnalysisResponse response;
+ // The response is an invalid serialization of protobuf, so this should fail
+ ASSERT_EQ(-1, MozAgentInfo.client->Send(request, &response));
+
+ BOOL terminateResult =
+ ::TerminateProcess(MozAgentInfo.processInfo.hProcess, 0);
+ ASSERT_NE(FALSE, terminateResult)
+ << "Failed to terminate content_analysis_sdk_agent process";
+}
+
+TEST(ContentAnalysisMisbehaving, MessageTruncatedInMiddleOfVarint)
+{
+ auto MozAgentInfo =
+ LaunchAgentMisbehaving(L"messageTruncatedInMiddleOfVarint");
+ // Exit the test early if the process failed to launch
+ ASSERT_NE(MozAgentInfo.processInfo.dwProcessId, 0UL);
+ ASSERT_NE(nullptr, MozAgentInfo.client.get());
+
+ ContentAnalysisRequest request;
+ request.set_request_token("request token");
+ ContentAnalysisResponse response;
+ // The response is an invalid serialization of protobuf, so this should fail
+ ASSERT_EQ(-1, MozAgentInfo.client->Send(request, &response));
+
+ BOOL terminateResult =
+ ::TerminateProcess(MozAgentInfo.processInfo.hProcess, 0);
+ ASSERT_NE(FALSE, terminateResult)
+ << "Failed to terminate content_analysis_sdk_agent process";
+}
+
+TEST(ContentAnalysisMisbehaving, MessageTruncatedInMiddleOfTag)
+{
+ auto MozAgentInfo = LaunchAgentMisbehaving(L"messageTruncatedInMiddleOfTag");
+ // Exit the test early if the process failed to launch
+ ASSERT_NE(MozAgentInfo.processInfo.dwProcessId, 0UL);
+ ASSERT_NE(nullptr, MozAgentInfo.client.get());
+
+ ContentAnalysisRequest request;
+ request.set_request_token("request token");
+ ContentAnalysisResponse response;
+ // The response is an invalid serialization of protobuf, so this should fail
+ ASSERT_EQ(-1, MozAgentInfo.client->Send(request, &response));
+
+ BOOL terminateResult =
+ ::TerminateProcess(MozAgentInfo.processInfo.hProcess, 0);
+ ASSERT_NE(FALSE, terminateResult)
+ << "Failed to terminate content_analysis_sdk_agent process";
+}
diff --git a/toolkit/components/contentanalysis/tests/gtest/TestContentAnalysisUtils.cpp b/toolkit/components/contentanalysis/tests/gtest/TestContentAnalysisUtils.cpp
new file mode 100644
index 0000000000..fc0cca5acd
--- /dev/null
+++ b/toolkit/components/contentanalysis/tests/gtest/TestContentAnalysisUtils.cpp
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+#include "TestContentAnalysis.h"
+#include <combaseapi.h>
+#include <pathcch.h>
+#include <shlwapi.h>
+#include <rpc.h>
+#include <windows.h>
+
+void GeneratePipeName(const wchar_t* prefix, nsString& pipeName) {
+ pipeName = u""_ns;
+ pipeName.Append(prefix);
+ UUID uuid;
+ ASSERT_EQ(RPC_S_OK, UuidCreate(&uuid));
+ // 39 == length of a UUID string including braces and NUL.
+ wchar_t guidBuf[39] = {};
+ ASSERT_EQ(39, StringFromGUID2(uuid, guidBuf, 39));
+ // omit opening and closing braces (and trailing null)
+ pipeName.Append(&guidBuf[1], 36);
+}
+
+void LaunchAgentWithCommandLineArguments(const nsString& cmdLineArguments,
+ const nsString& pipeName,
+ MozAgentInfo& agentInfo) {
+ wchar_t progName[MAX_PATH] = {};
+ // content_analysis_sdk_agent.exe is either next to firefox.exe (for local
+ // builds), or in ../../tests/bin/ (for try/treeherder builds)
+ DWORD nameSize = ::GetModuleFileNameW(nullptr, progName, MAX_PATH);
+ ASSERT_NE(DWORD{0}, nameSize);
+ ASSERT_EQ(S_OK, PathCchRemoveFileSpec(progName, nameSize));
+ wchar_t normalizedPath[MAX_PATH] = {};
+ nsString test1 = nsString(progName) + u"\\content_analysis_sdk_agent.exe"_ns;
+ ASSERT_EQ(S_OK, PathCchCanonicalize(normalizedPath, MAX_PATH, test1.get()));
+ nsString agentPath;
+ if (::PathFileExistsW(normalizedPath)) {
+ agentPath = nsString(normalizedPath);
+ }
+ if (agentPath.IsEmpty()) {
+ nsString unNormalizedPath =
+ nsString(progName) +
+ u"\\..\\..\\tests\\bin\\content_analysis_sdk_agent.exe"_ns;
+ ASSERT_EQ(S_OK, PathCchCanonicalize(normalizedPath, MAX_PATH,
+ unNormalizedPath.get()));
+ if (::PathFileExistsW(normalizedPath)) {
+ agentPath = nsString(normalizedPath);
+ }
+ }
+ ASSERT_FALSE(agentPath.IsEmpty());
+ nsString localCmdLine = nsString(agentPath) + u" "_ns + cmdLineArguments;
+ STARTUPINFOW startupInfo = {sizeof(startupInfo)};
+ PROCESS_INFORMATION processInfo;
+ BOOL ok =
+ ::CreateProcessW(nullptr, localCmdLine.get(), nullptr, nullptr, FALSE, 0,
+ nullptr, nullptr, &startupInfo, &processInfo);
+ // The documentation for CreateProcessW() says that any non-zero value is a
+ // success
+ if (!ok) {
+ // Show the last error
+ ASSERT_EQ(0UL, GetLastError())
+ << "Failed to launch content_analysis_sdk_agent";
+ }
+ // Allow time for the agent to set up the pipe
+ ::Sleep(2000);
+ content_analysis::sdk::Client::Config config;
+ config.name = NS_ConvertUTF16toUTF8(pipeName);
+ config.user_specific = true;
+ auto clientPtr = content_analysis::sdk::Client::Create(config);
+ ASSERT_NE(nullptr, clientPtr.get());
+
+ agentInfo.processInfo = processInfo;
+ agentInfo.client = std::move(clientPtr);
+}
diff --git a/toolkit/components/contentanalysis/tests/gtest/agent/moz.build b/toolkit/components/contentanalysis/tests/gtest/agent/moz.build
new file mode 100644
index 0000000000..71a3a029ed
--- /dev/null
+++ b/toolkit/components/contentanalysis/tests/gtest/agent/moz.build
@@ -0,0 +1,40 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+Program("content_analysis_sdk_agent")
+
+DEFINES["UNICODE"] = True
+DEFINES["GOOGLE_PROTOBUF_NO_RTTI"] = True
+DEFINES["GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER"] = True
+
+SOURCES += [
+ "../../../../../../third_party/content_analysis_sdk/agent/src/agent_base.cc",
+ "../../../../../../third_party/content_analysis_sdk/agent/src/agent_utils_win.cc",
+ "../../../../../../third_party/content_analysis_sdk/agent/src/agent_win.cc",
+ "../../../../../../third_party/content_analysis_sdk/agent/src/event_base.cc",
+ "../../../../../../third_party/content_analysis_sdk/agent/src/event_win.cc",
+ "../../../../../../third_party/content_analysis_sdk/agent/src/scoped_print_handle_base.cc",
+ "../../../../../../third_party/content_analysis_sdk/agent/src/scoped_print_handle_win.cc",
+ "../../../../../../third_party/content_analysis_sdk/common/utils_win.cc",
+ "../../../../../../third_party/content_analysis_sdk/demo/agent.cc",
+ "../../../content_analysis/sdk/analysis.pb.cc",
+]
+
+LOCAL_INCLUDES += [
+ "../../../",
+ "../../../../../../third_party/content_analysis_sdk",
+ "../../../../../../third_party/content_analysis_sdk/agent/include/",
+]
+
+USE_LIBS += [
+ "mozglue",
+ "protobuf",
+ "zlib",
+]
+
+OS_LIBS += [
+ "advapi32",
+]
diff --git a/toolkit/components/contentanalysis/tests/gtest/allowedFile.txt b/toolkit/components/contentanalysis/tests/gtest/allowedFile.txt
new file mode 100644
index 0000000000..1564d2d1bc
--- /dev/null
+++ b/toolkit/components/contentanalysis/tests/gtest/allowedFile.txt
@@ -0,0 +1 @@
+allow me \ No newline at end of file
diff --git a/toolkit/components/contentanalysis/tests/gtest/blockedFile.txt b/toolkit/components/contentanalysis/tests/gtest/blockedFile.txt
new file mode 100644
index 0000000000..58d958775d
--- /dev/null
+++ b/toolkit/components/contentanalysis/tests/gtest/blockedFile.txt
@@ -0,0 +1 @@
+block me \ No newline at end of file
diff --git a/toolkit/components/contentanalysis/tests/gtest/moz.build b/toolkit/components/contentanalysis/tests/gtest/moz.build
new file mode 100644
index 0000000000..ce701987a4
--- /dev/null
+++ b/toolkit/components/contentanalysis/tests/gtest/moz.build
@@ -0,0 +1,23 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+LOCAL_INCLUDES += [
+ "../..",
+ "../../../../../third_party/content_analysis_sdk/browser/include/",
+]
+
+if CONFIG["OS_TARGET"] == "WINNT":
+ UNIFIED_SOURCES += [
+ "TestContentAnalysis.cpp",
+ "TestContentAnalysisMisbehaving.cpp",
+ "TestContentAnalysisUtils.cpp",
+ ]
+ DIRS += ["agent"]
+ OS_LIBS += ["pathcch"]
+
+TEST_HARNESS_FILES.gtest += ["allowedFile.txt", "blockedFile.txt"]
+
+FINAL_LIBRARY = "xul-gtest"