1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "cronet_c.h"
6 
7 #include <limits>
8 
9 #include "base/allocator/buildflags.h"
10 #include "base/check.h"
11 #include "base/macros.h"
12 #include "base/run_loop.h"
13 #include "base/test/task_environment.h"
14 #include "components/cronet/native/test/test_util.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 
17 namespace {
18 
19 class BufferTest : public ::testing::Test {
20  public:
21   BufferTest() = default;
~BufferTest()22   ~BufferTest() override {}
23 
24  protected:
25   static void BufferCallback_OnDestroy(Cronet_BufferCallbackPtr self,
26                                        Cronet_BufferPtr buffer);
on_destroy_called() const27   bool on_destroy_called() const { return on_destroy_called_; }
28 
29   // Provide a task environment for use by TestExecutor instances. Do not
30   // initialize the ThreadPool as this is done by the Cronet_Engine
31   base::test::SingleThreadTaskEnvironment task_environment_;
32 
33  private:
set_on_destroy_called(bool value)34   void set_on_destroy_called(bool value) { on_destroy_called_ = value; }
35 
36   bool on_destroy_called_ = false;
37   DISALLOW_COPY_AND_ASSIGN(BufferTest);
38 };
39 
40 const uint64_t kTestBufferSize = 20;
41 
42 // static
BufferCallback_OnDestroy(Cronet_BufferCallbackPtr self,Cronet_BufferPtr buffer)43 void BufferTest::BufferCallback_OnDestroy(Cronet_BufferCallbackPtr self,
44                                           Cronet_BufferPtr buffer) {
45   CHECK(self);
46   Cronet_ClientContext context = Cronet_BufferCallback_GetClientContext(self);
47   BufferTest* test = static_cast<BufferTest*>(context);
48   CHECK(test);
49   test->set_on_destroy_called(true);
50   // Free buffer_data.
51   void* buffer_data = Cronet_Buffer_GetData(buffer);
52   CHECK(buffer_data);
53   free(buffer_data);
54 }
55 
56 // Test on_destroy that destroys the buffer set in context.
TestRunnable_DestroyBuffer(Cronet_RunnablePtr self)57 void TestRunnable_DestroyBuffer(Cronet_RunnablePtr self) {
58   CHECK(self);
59   Cronet_ClientContext context = Cronet_Runnable_GetClientContext(self);
60   Cronet_BufferPtr buffer = static_cast<Cronet_BufferPtr>(context);
61   CHECK(buffer);
62   // Destroy buffer. TestCronet_BufferCallback_OnDestroy should be invoked.
63   Cronet_Buffer_Destroy(buffer);
64 }
65 
66 // Example of allocating buffer with reasonable size.
TEST_F(BufferTest,TestInitWithAlloc)67 TEST_F(BufferTest, TestInitWithAlloc) {
68   // Create Cronet buffer and allocate buffer data.
69   Cronet_BufferPtr buffer = Cronet_Buffer_Create();
70   Cronet_Buffer_InitWithAlloc(buffer, kTestBufferSize);
71   EXPECT_TRUE(Cronet_Buffer_GetData(buffer));
72   EXPECT_EQ(Cronet_Buffer_GetSize(buffer), kTestBufferSize);
73   Cronet_Buffer_Destroy(buffer);
74   ASSERT_FALSE(on_destroy_called());
75 }
76 
77 #if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \
78     defined(THREAD_SANITIZER) || defined(OS_FUCHSIA) ||        \
79     BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
80 // ASAN and MSAN malloc by default triggers crash instead of returning null on
81 // failure. Fuchsia malloc() also crashes on allocation failure in some kernel
82 // builds. PartitionAlloc malloc also crashes on allocation failure by design.
83 #define MAYBE_TestInitWithHugeAllocFails DISABLED_TestInitWithHugeAllocFails
84 #else
85 #define MAYBE_TestInitWithHugeAllocFails TestInitWithHugeAllocFails
86 #endif
87 // Verify behaviour when an unsatisfiably huge buffer allocation is requested.
88 // On 32-bit platforms, we want to ensure that a 64-bit range allocation size
89 // is rejected, rather than resulting in a 32-bit truncated allocation.
90 // Some platforms over-commit allocations, so we request an allocation of the
91 // whole 64-bit address-space, which cannot possibly be satisfied in a 32- or
92 // 64-bit process.
TEST_F(BufferTest,MAYBE_TestInitWithHugeAllocFails)93 TEST_F(BufferTest, MAYBE_TestInitWithHugeAllocFails) {
94   Cronet_BufferPtr buffer = Cronet_Buffer_Create();
95   const uint64_t kHugeTestBufferSize = std::numeric_limits<uint64_t>::max();
96   Cronet_Buffer_InitWithAlloc(buffer, kHugeTestBufferSize);
97   EXPECT_FALSE(Cronet_Buffer_GetData(buffer));
98   EXPECT_EQ(Cronet_Buffer_GetSize(buffer), 0ull);
99   Cronet_Buffer_Destroy(buffer);
100   ASSERT_FALSE(on_destroy_called());
101 }
102 
103 // Example of initializing buffer with app-allocated data.
TEST_F(BufferTest,TestInitWithDataAndCallback)104 TEST_F(BufferTest, TestInitWithDataAndCallback) {
105   Cronet_BufferCallbackPtr buffer_callback =
106       Cronet_BufferCallback_CreateWith(BufferCallback_OnDestroy);
107   Cronet_BufferCallback_SetClientContext(buffer_callback, this);
108   // Create Cronet buffer and allocate buffer data.
109   Cronet_BufferPtr buffer = Cronet_Buffer_Create();
110   Cronet_Buffer_InitWithDataAndCallback(buffer, malloc(kTestBufferSize),
111                                         kTestBufferSize, buffer_callback);
112   EXPECT_TRUE(Cronet_Buffer_GetData(buffer));
113   EXPECT_EQ(Cronet_Buffer_GetSize(buffer), kTestBufferSize);
114   Cronet_Buffer_Destroy(buffer);
115   ASSERT_TRUE(on_destroy_called());
116   Cronet_BufferCallback_Destroy(buffer_callback);
117 }
118 
119 // Example of posting application on_destroy to the executor and passing
120 // buffer to it, expecting buffer to be destroyed and freed.
TEST_F(BufferTest,TestCronetBufferAsync)121 TEST_F(BufferTest, TestCronetBufferAsync) {
122   // Executor provided by the application.
123   Cronet_ExecutorPtr executor = cronet::test::CreateTestExecutor();
124   Cronet_BufferCallbackPtr buffer_callback =
125       Cronet_BufferCallback_CreateWith(BufferCallback_OnDestroy);
126   Cronet_BufferCallback_SetClientContext(buffer_callback, this);
127   // Create Cronet buffer and allocate buffer data.
128   Cronet_BufferPtr buffer = Cronet_Buffer_Create();
129   Cronet_Buffer_InitWithDataAndCallback(buffer, malloc(kTestBufferSize),
130                                         kTestBufferSize, buffer_callback);
131   Cronet_RunnablePtr runnable =
132       Cronet_Runnable_CreateWith(TestRunnable_DestroyBuffer);
133   Cronet_Runnable_SetClientContext(runnable, buffer);
134   Cronet_Executor_Execute(executor, runnable);
135   base::RunLoop().RunUntilIdle();
136   ASSERT_TRUE(on_destroy_called());
137   Cronet_Executor_Destroy(executor);
138   Cronet_BufferCallback_Destroy(buffer_callback);
139 }
140 
141 }  // namespace
142