Run all tests with lots of encoding threads.
[dcpomatic.git] / test / socket_test.cc
1 /*
2     Copyright (C) 2020 Carl Hetherington <cth@carlh.net>
3
4     This file is part of DCP-o-matic.
5
6     DCP-o-matic is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     DCP-o-matic is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
18
19 */
20
21 #include "lib/server.h"
22 #include "lib/dcpomatic_socket.h"
23 #include <boost/thread.hpp>
24 #include <boost/test/unit_test.hpp>
25 #include <boost/shared_ptr.hpp>
26 #include <cstring>
27 #include <iostream>
28
29 using boost::shared_ptr;
30 using boost::bind;
31
32 #define TEST_SERVER_PORT 9142
33 #define TEST_SERVER_BUFFER_LENGTH 1024
34
35
36 class TestServer : public Server
37 {
38 public:
39         TestServer (bool digest)
40                 : Server (TEST_SERVER_PORT, 30)
41                 , _buffer (new uint8_t[TEST_SERVER_BUFFER_LENGTH])
42                 , _size (0)
43                 , _result (false)
44                 , _digest (digest)
45         {
46                 _thread = boost::thread(bind(&TestServer::run, this));
47         }
48
49         ~TestServer ()
50         {
51                 stop ();
52                 _thread.join ();
53                 delete[] _buffer;
54         }
55
56         void expect (int size)
57         {
58                 boost::mutex::scoped_lock lm (_mutex);
59                 _size = size;
60         }
61
62         uint8_t const * buffer() const {
63                 return _buffer;
64         }
65
66         void await ()
67         {
68                 boost::mutex::scoped_lock lm (_mutex);
69                 if (_size) {
70                         _condition.wait (lm);
71                 }
72         }
73
74         bool result () const {
75                 return _result;
76         }
77
78 private:
79         void handle (boost::shared_ptr<Socket> socket)
80         {
81                 boost::mutex::scoped_lock lm (_mutex);
82                 BOOST_REQUIRE (_size);
83                 if (_digest) {
84                         Socket::ReadDigestScope ds (socket);
85                         socket->read (_buffer, _size);
86                         _size = 0;
87                         _condition.notify_one ();
88                         _result = ds.check();
89                 } else {
90                         socket->read (_buffer, _size);
91                         _size = 0;
92                         _condition.notify_one ();
93                 }
94         }
95
96         boost::thread _thread;
97         boost::mutex _mutex;
98         boost::condition _condition;
99         uint8_t* _buffer;
100         int _size;
101         bool _result;
102         bool _digest;
103 };
104
105
106 void
107 send (shared_ptr<Socket> socket, char const* message)
108 {
109         socket->write (reinterpret_cast<uint8_t const *>(message), strlen(message) + 1);
110 }
111
112 /** Basic test to see if Socket can send and receive data */
113 BOOST_AUTO_TEST_CASE (socket_basic_test)
114 {
115         TestServer server(false);
116         server.expect (13);
117
118         shared_ptr<Socket> socket (new Socket);
119         socket->connect (boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), TEST_SERVER_PORT));
120         send (socket, "Hello world!");
121
122         server.await ();
123         BOOST_CHECK_EQUAL(strcmp(reinterpret_cast<char const *>(server.buffer()), "Hello world!"), 0);
124 }
125
126
127 /** Check that the socket "auto-digest" creation works */
128 BOOST_AUTO_TEST_CASE (socket_digest_test1)
129 {
130         TestServer server(false);
131         server.expect (13 + 16);
132
133         shared_ptr<Socket> socket(new Socket);
134         socket->connect (boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), TEST_SERVER_PORT));
135         {
136                 Socket::WriteDigestScope ds(socket);
137                 send (socket, "Hello world!");
138         }
139
140         server.await ();
141         BOOST_CHECK_EQUAL(strcmp(reinterpret_cast<char const *>(server.buffer()), "Hello world!"), 0);
142
143         /* printf "%s\0" "Hello world!" | md5sum" in bash */
144         char ref[] = "\x59\x86\x88\xed\x18\xc8\x71\xdd\x57\xb9\xb7\x9f\x4b\x03\x14\xcf";
145         BOOST_CHECK_EQUAL (memcmp(server.buffer() + 13, ref, 16), 0);
146 }
147
148
149 /** Check that the socket "auto-digest" round-trip works */
150 BOOST_AUTO_TEST_CASE (socket_digest_test2)
151 {
152         TestServer server(true);
153         server.expect (13);
154
155         shared_ptr<Socket> socket(new Socket);
156         socket->connect (boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), TEST_SERVER_PORT));
157         {
158                 Socket::WriteDigestScope ds(socket);
159                 send (socket, "Hello world!");
160         }
161
162         server.await ();
163         BOOST_CHECK_EQUAL(strcmp(reinterpret_cast<char const *>(server.buffer()), "Hello world!"), 0);
164
165         BOOST_CHECK (server.result());
166 }
167