1 // Copyright (c) 2011 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 // Tests for the command parser. 6 7 #include "base/logging.h" 8 #include "base/memory/scoped_ptr.h" 9 #include "gpu/command_buffer/service/cmd_parser.h" 10 #include "gpu/command_buffer/service/mocks.h" 11 #include "testing/gtest/include/gtest/gtest.h" 12 13 namespace gpu { 14 15 using testing::_; 16 using testing::Invoke; 17 using testing::Mock; 18 using testing::Return; 19 using testing::Sequence; 20 using testing::SetArgPointee; 21 using testing::Truly; 22 23 // Test fixture for CommandParser test - Creates a mock AsyncAPIInterface, and 24 // a fixed size memory buffer. Also provides a simple API to create a 25 // CommandParser. 26 class CommandParserTest : public testing::Test { 27 protected: 28 virtual void SetUp() { 29 api_mock_.reset(new AsyncAPIMock(false)); 30 buffer_entry_count_ = 20; 31 buffer_.reset(new CommandBufferEntry[buffer_entry_count_]); 32 } 33 virtual void TearDown() {} 34 35 void AddDoCommandsExpect(error::Error _return, 36 unsigned int num_commands, 37 int num_entries, 38 int num_processed) { 39 EXPECT_CALL(*api_mock_, DoCommands(num_commands, _, num_entries, _)) 40 .InSequence(sequence_) 41 .WillOnce(DoAll(SetArgPointee<3>(num_processed), Return(_return))); 42 } 43 44 // Creates a parser, with a buffer of the specified size (in entries). 45 CommandParser *MakeParser(unsigned int entry_count) { 46 size_t shm_size = buffer_entry_count_ * 47 sizeof(CommandBufferEntry); // NOLINT 48 size_t command_buffer_size = entry_count * 49 sizeof(CommandBufferEntry); // NOLINT 50 DCHECK_LE(command_buffer_size, shm_size); 51 CommandParser* parser = new CommandParser(api_mock()); 52 53 parser->SetBuffer(buffer(), shm_size, 0, command_buffer_size); 54 return parser; 55 } 56 57 unsigned int buffer_entry_count() { return 20; } 58 AsyncAPIMock *api_mock() { return api_mock_.get(); } 59 CommandBufferEntry *buffer() { return buffer_.get(); } 60 private: 61 unsigned int buffer_entry_count_; 62 scoped_ptr<AsyncAPIMock> api_mock_; 63 scoped_ptr<CommandBufferEntry[]> buffer_; 64 Sequence sequence_; 65 }; 66 67 // Tests initialization conditions. 68 TEST_F(CommandParserTest, TestInit) { 69 scoped_ptr<CommandParser> parser(MakeParser(10)); 70 EXPECT_EQ(0, parser->get()); 71 EXPECT_EQ(0, parser->put()); 72 EXPECT_TRUE(parser->IsEmpty()); 73 } 74 75 // Tests simple commands. 76 TEST_F(CommandParserTest, TestSimple) { 77 scoped_ptr<CommandParser> parser(MakeParser(10)); 78 CommandBufferOffset put = parser->put(); 79 CommandHeader header; 80 81 // add a single command, no args 82 header.size = 1; 83 header.command = 123; 84 buffer()[put++].value_header = header; 85 parser->set_put(put); 86 EXPECT_EQ(put, parser->put()); 87 88 AddDoCommandsExpect(error::kNoError, 1, 1, 1); 89 EXPECT_EQ(error::kNoError, parser->ProcessCommands(1)); 90 EXPECT_EQ(put, parser->get()); 91 Mock::VerifyAndClearExpectations(api_mock()); 92 93 // add a single command, 2 args 94 header.size = 3; 95 header.command = 456; 96 buffer()[put++].value_header = header; 97 buffer()[put++].value_int32 = 2134; 98 buffer()[put++].value_float = 1.f; 99 parser->set_put(put); 100 EXPECT_EQ(put, parser->put()); 101 102 AddDoCommandsExpect(error::kNoError, 1, 3, 3); 103 EXPECT_EQ(error::kNoError, parser->ProcessCommands(1)); 104 EXPECT_EQ(put, parser->get()); 105 Mock::VerifyAndClearExpectations(api_mock()); 106 } 107 108 // Tests having multiple commands in the buffer. 109 TEST_F(CommandParserTest, TestMultipleCommands) { 110 scoped_ptr<CommandParser> parser(MakeParser(10)); 111 CommandBufferOffset put = parser->put(); 112 CommandHeader header; 113 114 // add 2 commands, test with single ProcessCommands() 115 header.size = 2; 116 header.command = 789; 117 buffer()[put++].value_header = header; 118 buffer()[put++].value_int32 = 5151; 119 120 CommandBufferOffset put_cmd2 = put; 121 header.size = 2; 122 header.command = 876; 123 buffer()[put++].value_header = header; 124 buffer()[put++].value_int32 = 3434; 125 parser->set_put(put); 126 EXPECT_EQ(put, parser->put()); 127 128 // Process up to 1 command. 4 entries remaining. 129 AddDoCommandsExpect(error::kNoError, 1, 4, 2); 130 EXPECT_EQ(error::kNoError, parser->ProcessCommands(1)); 131 EXPECT_EQ(put_cmd2, parser->get()); 132 133 // Process up to 1 command. 2 entries remaining. 134 AddDoCommandsExpect(error::kNoError, 1, 2, 2); 135 EXPECT_EQ(error::kNoError, parser->ProcessCommands(1)); 136 EXPECT_EQ(put, parser->get()); 137 Mock::VerifyAndClearExpectations(api_mock()); 138 139 // add 2 commands again, test with ProcessAllCommands() 140 header.size = 2; 141 header.command = 123; 142 buffer()[put++].value_header = header; 143 buffer()[put++].value_int32 = 5656; 144 145 header.size = 2; 146 header.command = 321; 147 buffer()[put++].value_header = header; 148 buffer()[put++].value_int32 = 7878; 149 parser->set_put(put); 150 EXPECT_EQ(put, parser->put()); 151 152 // 4 entries remaining. 153 AddDoCommandsExpect( 154 error::kNoError, CommandParser::kParseCommandsSlice, 4, 4); 155 EXPECT_EQ(error::kNoError, parser->ProcessAllCommands()); 156 EXPECT_EQ(put, parser->get()); 157 Mock::VerifyAndClearExpectations(api_mock()); 158 } 159 160 // Tests that the parser will wrap correctly at the end of the buffer. 161 TEST_F(CommandParserTest, TestWrap) { 162 scoped_ptr<CommandParser> parser(MakeParser(5)); 163 CommandBufferOffset put = parser->put(); 164 CommandHeader header; 165 166 // add 3 commands with no args (1 word each) 167 for (unsigned int i = 0; i < 3; ++i) { 168 header.size = 1; 169 header.command = i; 170 buffer()[put++].value_header = header; 171 } 172 parser->set_put(put); 173 EXPECT_EQ(put, parser->put()); 174 175 // Process up to 10 commands. 3 entries remaining to put. 176 AddDoCommandsExpect(error::kNoError, 10, 3, 3); 177 EXPECT_EQ(error::kNoError, parser->ProcessCommands(10)); 178 EXPECT_EQ(put, parser->get()); 179 Mock::VerifyAndClearExpectations(api_mock()); 180 181 // add 1 command with 1 arg (2 words). That should put us at the end of the 182 // buffer. 183 header.size = 2; 184 header.command = 3; 185 buffer()[put++].value_header = header; 186 buffer()[put++].value_int32 = 5; 187 188 DCHECK_EQ(5, put); 189 put = 0; 190 191 // add 1 command with 1 arg (2 words). 192 header.size = 2; 193 header.command = 4; 194 buffer()[put++].value_header = header; 195 buffer()[put++].value_int32 = 6; 196 197 // 2 entries remaining to end of buffer. 198 AddDoCommandsExpect( 199 error::kNoError, CommandParser::kParseCommandsSlice, 2, 2); 200 // 2 entries remaining to put. 201 AddDoCommandsExpect( 202 error::kNoError, CommandParser::kParseCommandsSlice, 2, 2); 203 parser->set_put(put); 204 EXPECT_EQ(put, parser->put()); 205 206 EXPECT_EQ(error::kNoError, parser->ProcessAllCommands()); 207 EXPECT_EQ(put, parser->get()); 208 Mock::VerifyAndClearExpectations(api_mock()); 209 } 210 211 // Tests error conditions. 212 TEST_F(CommandParserTest, TestError) { 213 const unsigned int kNumEntries = 5; 214 scoped_ptr<CommandParser> parser(MakeParser(kNumEntries)); 215 CommandBufferOffset put = parser->put(); 216 CommandHeader header; 217 218 EXPECT_FALSE(parser->set_get(-1)); 219 EXPECT_FALSE(parser->set_get(kNumEntries)); 220 221 // Generate a command with size 0. 222 header.size = 0; 223 header.command = 3; 224 buffer()[put++].value_header = header; 225 226 parser->set_put(put); 227 EXPECT_EQ(put, parser->put()); 228 229 AddDoCommandsExpect( 230 error::kInvalidSize, CommandParser::kParseCommandsSlice, 1, 0); 231 EXPECT_EQ(error::kInvalidSize, 232 parser->ProcessAllCommands()); 233 // check that no DoCommand call was made. 234 Mock::VerifyAndClearExpectations(api_mock()); 235 236 parser.reset(MakeParser(5)); 237 put = parser->put(); 238 239 // Generate a command with size 6, extends beyond the end of the buffer. 240 header.size = 6; 241 header.command = 3; 242 buffer()[put++].value_header = header; 243 244 parser->set_put(put); 245 EXPECT_EQ(put, parser->put()); 246 247 AddDoCommandsExpect( 248 error::kOutOfBounds, CommandParser::kParseCommandsSlice, 1, 0); 249 EXPECT_EQ(error::kOutOfBounds, 250 parser->ProcessAllCommands()); 251 // check that no DoCommand call was made. 252 Mock::VerifyAndClearExpectations(api_mock()); 253 254 parser.reset(MakeParser(5)); 255 put = parser->put(); 256 257 // Generates 2 commands. 258 header.size = 1; 259 header.command = 3; 260 buffer()[put++].value_header = header; 261 CommandBufferOffset put_post_fail = put; 262 header.size = 1; 263 header.command = 4; 264 buffer()[put++].value_header = header; 265 266 parser->set_put(put); 267 EXPECT_EQ(put, parser->put()); 268 // have the first command fail to parse. 269 AddDoCommandsExpect( 270 error::kUnknownCommand, CommandParser::kParseCommandsSlice, 2, 1); 271 EXPECT_EQ(error::kUnknownCommand, 272 parser->ProcessAllCommands()); 273 // check that only one command was executed, and that get reflects that 274 // correctly. 275 EXPECT_EQ(put_post_fail, parser->get()); 276 Mock::VerifyAndClearExpectations(api_mock()); 277 // make the second one succeed, and check that the parser recovered fine. 278 AddDoCommandsExpect( 279 error::kNoError, CommandParser::kParseCommandsSlice, 1, 1); 280 EXPECT_EQ(error::kNoError, parser->ProcessAllCommands()); 281 EXPECT_EQ(put, parser->get()); 282 Mock::VerifyAndClearExpectations(api_mock()); 283 } 284 285 TEST_F(CommandParserTest, SetBuffer) { 286 scoped_ptr<CommandParser> parser(MakeParser(3)); 287 CommandBufferOffset put = parser->put(); 288 CommandHeader header; 289 290 // add a single command, no args 291 header.size = 2; 292 header.command = 123; 293 buffer()[put++].value_header = header; 294 buffer()[put++].value_int32 = 456; 295 parser->set_put(put); 296 297 AddDoCommandsExpect( 298 error::kNoError, CommandParser::kParseCommandsSlice, 2, 2); 299 EXPECT_EQ(error::kNoError, parser->ProcessAllCommands()); 300 // We should have advanced 2 entries 301 EXPECT_EQ(2, parser->get()); 302 Mock::VerifyAndClearExpectations(api_mock()); 303 304 scoped_ptr<CommandBufferEntry[]> buffer2(new CommandBufferEntry[2]); 305 parser->SetBuffer( 306 buffer2.get(), sizeof(CommandBufferEntry) * 2, 0, 307 sizeof(CommandBufferEntry) * 2); 308 // The put and get should have reset to 0. 309 EXPECT_EQ(0, parser->get()); 310 EXPECT_EQ(0, parser->put()); 311 } 312 313 } // namespace gpu 314