Home | History | Annotate | Download | only in service
      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::Return;
     16 using testing::Mock;
     17 using testing::Truly;
     18 using testing::Sequence;
     19 using testing::_;
     20 
     21 // Test fixture for CommandParser test - Creates a mock AsyncAPIInterface, and
     22 // a fixed size memory buffer. Also provides a simple API to create a
     23 // CommandParser.
     24 class CommandParserTest : public testing::Test {
     25  protected:
     26   virtual void SetUp() {
     27     api_mock_.reset(new AsyncAPIMock);
     28     buffer_entry_count_ = 20;
     29     buffer_.reset(new CommandBufferEntry[buffer_entry_count_]);
     30   }
     31   virtual void TearDown() {}
     32 
     33   // Adds a DoCommand expectation in the mock.
     34   void AddDoCommandExpect(error::Error _return,
     35                           unsigned int command,
     36                           unsigned int arg_count,
     37                           CommandBufferEntry *args) {
     38     EXPECT_CALL(*api_mock(), DoCommand(command, arg_count,
     39         Truly(AsyncAPIMock::IsArgs(arg_count, args))))
     40         .InSequence(sequence_)
     41         .WillOnce(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 
     86   parser->set_put(put);
     87   EXPECT_EQ(put, parser->put());
     88 
     89   AddDoCommandExpect(error::kNoError, 123, 0, NULL);
     90   EXPECT_EQ(error::kNoError, parser->ProcessCommand());
     91   EXPECT_EQ(put, parser->get());
     92   Mock::VerifyAndClearExpectations(api_mock());
     93 
     94   // add a single command, 2 args
     95   header.size = 3;
     96   header.command = 456;
     97   buffer()[put++].value_header = header;
     98   buffer()[put++].value_int32 = 2134;
     99   buffer()[put++].value_float = 1.f;
    100 
    101   parser->set_put(put);
    102   EXPECT_EQ(put, parser->put());
    103 
    104   CommandBufferEntry param_array[2];
    105   param_array[0].value_int32 = 2134;
    106   param_array[1].value_float = 1.f;
    107   AddDoCommandExpect(error::kNoError, 456, 2, param_array);
    108   EXPECT_EQ(error::kNoError, parser->ProcessCommand());
    109   EXPECT_EQ(put, parser->get());
    110   Mock::VerifyAndClearExpectations(api_mock());
    111 }
    112 
    113 // Tests having multiple commands in the buffer.
    114 TEST_F(CommandParserTest, TestMultipleCommands) {
    115   scoped_ptr<CommandParser> parser(MakeParser(10));
    116   CommandBufferOffset put = parser->put();
    117   CommandHeader header;
    118 
    119   // add 2 commands, test with single ProcessCommand()
    120   header.size = 2;
    121   header.command = 789;
    122   buffer()[put++].value_header = header;
    123   buffer()[put++].value_int32 = 5151;
    124 
    125   CommandBufferOffset put_cmd2 = put;
    126   header.size = 2;
    127   header.command = 876;
    128   buffer()[put++].value_header = header;
    129   buffer()[put++].value_int32 = 3434;
    130 
    131   parser->set_put(put);
    132   EXPECT_EQ(put, parser->put());
    133 
    134   CommandBufferEntry param_array[2];
    135   param_array[0].value_int32 = 5151;
    136   AddDoCommandExpect(error::kNoError, 789, 1, param_array);
    137   param_array[1].value_int32 = 3434;
    138   AddDoCommandExpect(error::kNoError, 876, 1,
    139                      param_array+1);
    140 
    141   EXPECT_EQ(error::kNoError, parser->ProcessCommand());
    142   EXPECT_EQ(put_cmd2, parser->get());
    143   EXPECT_EQ(error::kNoError, parser->ProcessCommand());
    144   EXPECT_EQ(put, parser->get());
    145   Mock::VerifyAndClearExpectations(api_mock());
    146 
    147   // add 2 commands again, test with ProcessAllCommands()
    148   header.size = 2;
    149   header.command = 123;
    150   buffer()[put++].value_header = header;
    151   buffer()[put++].value_int32 = 5656;
    152 
    153   header.size = 2;
    154   header.command = 321;
    155   buffer()[put++].value_header = header;
    156   buffer()[put++].value_int32 = 7878;
    157 
    158   parser->set_put(put);
    159   EXPECT_EQ(put, parser->put());
    160 
    161   param_array[0].value_int32 = 5656;
    162   AddDoCommandExpect(error::kNoError, 123, 1, param_array);
    163   param_array[1].value_int32 = 7878;
    164   AddDoCommandExpect(error::kNoError, 321, 1,
    165                      param_array+1);
    166 
    167   EXPECT_EQ(error::kNoError, parser->ProcessAllCommands());
    168   EXPECT_EQ(put, parser->get());
    169   Mock::VerifyAndClearExpectations(api_mock());
    170 }
    171 
    172 // Tests that the parser will wrap correctly at the end of the buffer.
    173 TEST_F(CommandParserTest, TestWrap) {
    174   scoped_ptr<CommandParser> parser(MakeParser(5));
    175   CommandBufferOffset put = parser->put();
    176   CommandHeader header;
    177 
    178   // add 3 commands with no args (1 word each)
    179   for (unsigned int i = 0; i < 3; ++i) {
    180     header.size = 1;
    181     header.command = i;
    182     buffer()[put++].value_header = header;
    183     AddDoCommandExpect(error::kNoError, i, 0, NULL);
    184   }
    185   parser->set_put(put);
    186   EXPECT_EQ(put, parser->put());
    187   EXPECT_EQ(error::kNoError, parser->ProcessAllCommands());
    188   EXPECT_EQ(put, parser->get());
    189   Mock::VerifyAndClearExpectations(api_mock());
    190 
    191   // add 1 command with 1 arg (2 words). That should put us at the end of the
    192   // buffer.
    193   header.size = 2;
    194   header.command = 3;
    195   buffer()[put++].value_header = header;
    196   buffer()[put++].value_int32 = 5;
    197   CommandBufferEntry param;
    198   param.value_int32 = 5;
    199   AddDoCommandExpect(error::kNoError, 3, 1, &param);
    200 
    201   DCHECK_EQ(5, put);
    202   put = 0;
    203   parser->set_put(put);
    204   EXPECT_EQ(put, parser->put());
    205   EXPECT_EQ(error::kNoError, parser->ProcessAllCommands());
    206   EXPECT_EQ(put, parser->get());
    207   Mock::VerifyAndClearExpectations(api_mock());
    208 
    209   // add 1 command with 1 arg (2 words).
    210   header.size = 2;
    211   header.command = 4;
    212   buffer()[put++].value_header = header;
    213   buffer()[put++].value_int32 = 6;
    214   param.value_int32 = 6;
    215   AddDoCommandExpect(error::kNoError, 4, 1, &param);
    216   parser->set_put(put);
    217   EXPECT_EQ(put, parser->put());
    218   EXPECT_EQ(error::kNoError, parser->ProcessAllCommands());
    219   EXPECT_EQ(put, parser->get());
    220   Mock::VerifyAndClearExpectations(api_mock());
    221 }
    222 
    223 // Tests error conditions.
    224 TEST_F(CommandParserTest, TestError) {
    225   const unsigned int kNumEntries = 5;
    226   scoped_ptr<CommandParser> parser(MakeParser(kNumEntries));
    227   CommandBufferOffset put = parser->put();
    228   CommandHeader header;
    229 
    230   EXPECT_FALSE(parser->set_get(-1));
    231   EXPECT_FALSE(parser->set_get(kNumEntries));
    232 
    233   // Generate a command with size 0.
    234   header.size = 0;
    235   header.command = 3;
    236   buffer()[put++].value_header = header;
    237 
    238   parser->set_put(put);
    239   EXPECT_EQ(put, parser->put());
    240   EXPECT_EQ(error::kInvalidSize,
    241             parser->ProcessAllCommands());
    242   // check that no DoCommand call was made.
    243   Mock::VerifyAndClearExpectations(api_mock());
    244 
    245   parser.reset(MakeParser(5));
    246   put = parser->put();
    247 
    248   // Generate a command with size 6, extends beyond the end of the buffer.
    249   header.size = 6;
    250   header.command = 3;
    251   buffer()[put++].value_header = header;
    252 
    253   parser->set_put(put);
    254   EXPECT_EQ(put, parser->put());
    255   EXPECT_EQ(error::kOutOfBounds,
    256             parser->ProcessAllCommands());
    257   // check that no DoCommand call was made.
    258   Mock::VerifyAndClearExpectations(api_mock());
    259 
    260   parser.reset(MakeParser(5));
    261   put = parser->put();
    262 
    263   // Generates 2 commands.
    264   header.size = 1;
    265   header.command = 3;
    266   buffer()[put++].value_header = header;
    267   CommandBufferOffset put_post_fail = put;
    268   header.size = 1;
    269   header.command = 4;
    270   buffer()[put++].value_header = header;
    271 
    272   parser->set_put(put);
    273   EXPECT_EQ(put, parser->put());
    274   // have the first command fail to parse.
    275   AddDoCommandExpect(error::kUnknownCommand, 3, 0, NULL);
    276   EXPECT_EQ(error::kUnknownCommand,
    277             parser->ProcessAllCommands());
    278   // check that only one command was executed, and that get reflects that
    279   // correctly.
    280   EXPECT_EQ(put_post_fail, parser->get());
    281   Mock::VerifyAndClearExpectations(api_mock());
    282   // make the second one succeed, and check that the parser recovered fine.
    283   AddDoCommandExpect(error::kNoError, 4, 0, NULL);
    284   EXPECT_EQ(error::kNoError, parser->ProcessAllCommands());
    285   EXPECT_EQ(put, parser->get());
    286   Mock::VerifyAndClearExpectations(api_mock());
    287 }
    288 
    289 TEST_F(CommandParserTest, SetBuffer) {
    290   scoped_ptr<CommandParser> parser(MakeParser(3));
    291   CommandBufferOffset put = parser->put();
    292   CommandHeader header;
    293 
    294   // add a single command, no args
    295   header.size = 2;
    296   header.command = 123;
    297   buffer()[put++].value_header = header;
    298   buffer()[put++].value_int32 = 456;
    299 
    300   CommandBufferEntry param_array[1];
    301   param_array[0].value_int32 = 456;
    302 
    303   parser->set_put(put);
    304   AddDoCommandExpect(error::kNoError, 123, 1, param_array);
    305   EXPECT_EQ(error::kNoError, parser->ProcessAllCommands());
    306   // We should have advanced 2 entries
    307   EXPECT_EQ(2, parser->get());
    308   Mock::VerifyAndClearExpectations(api_mock());
    309 
    310   scoped_ptr<CommandBufferEntry[]> buffer2(new CommandBufferEntry[2]);
    311   parser->SetBuffer(
    312       buffer2.get(), sizeof(CommandBufferEntry) * 2, 0,
    313       sizeof(CommandBufferEntry) * 2);
    314   // The put and get should have reset to 0.
    315   EXPECT_EQ(0, parser->get());
    316   EXPECT_EQ(0, parser->put());
    317 }
    318 
    319 }  // namespace gpu
    320