RTBKit  0.9
Open-source framework to create real-time ad bidding systems.
plugins/bid_request/testing/openrtb_bid_request_test.cc
00001 /* openrtb_bid_request_test.cc
00002    Jeremy Barnes, 19 February 2013
00003    Copyright (c) 2013 Datacratic Inc.  All rights reserved.
00004 
00005    Test cases for the OpenRTB bid request parser.
00006 */
00007 
00008 
00009 #define BOOST_TEST_MAIN
00010 #define BOOST_TEST_DYN_LINK
00011 
00012 #include <boost/test/unit_test.hpp>
00013 #include "rtbkit/plugins/bid_request/openrtb_bid_request.h"
00014 #include "soa/types/json_parsing.h"
00015 #include "openrtb/openrtb_parsing.h"
00016 #include "jml/utils/filter_streams.h"
00017 
00018 using namespace std;
00019 using namespace ML;
00020 using namespace Datacratic;
00021 using namespace RTBKIT;
00022 
00023 vector<string> samples = {
00024     "rtbkit/plugins/bid_request/testing/openrtb1_req.json",
00025     "rtbkit/plugins/bid_request/testing/openrtb2_req.json",
00026     "rtbkit/plugins/bid_request/testing/openrtb_banner.json",
00027     "rtbkit/plugins/bid_request/testing/openrtb_expandable_creative.json",
00028     "rtbkit/plugins/bid_request/testing/openrtb_mobile.json",
00029     "rtbkit/plugins/bid_request/testing/openrtb_video.json",
00030     "rtbkit/plugins/bid_request/testing/rubicon_banner1.json",
00031     "rtbkit/plugins/bid_request/testing/rubicon_banner2.json",
00032     "rtbkit/plugins/bid_request/testing/rubicon_banner3.json",
00033     "rtbkit/plugins/bid_request/testing/rubicon_banner4.json",
00034     "rtbkit/plugins/bid_request/testing/rubicon_desktop.json",
00035     "rtbkit/plugins/bid_request/testing/rubicon_mobile_app.json",
00036     "rtbkit/plugins/bid_request/testing/rubicon_mobile_web.json",
00037     "rtbkit/plugins/bid_request/testing/rubicon_test1.json"
00038 };
00039 
00040 std::string loadFile(const std::string & filename)
00041 {
00042     ML::filter_istream stream(filename);
00043     
00044     string result;
00045     
00046     while (stream) {
00047         string line;
00048         getline(stream, line);
00049         result += line + "\n";
00050     }
00051 
00052     return result;
00053 }
00054 
00055 void parseBidRequest(const std::string & filename)
00056 {
00057     cerr << endl << "loading " << filename << endl;
00058     StreamingJsonParsingContext context;
00059     context.init(filename);
00060 
00061     OpenRTB::BidRequest req;
00062     DefaultDescription<OpenRTB::BidRequest> desc;
00063     desc.parseJson(&req, context);
00064 
00065     if (!req.unparseable.isNull())
00066         cerr << "unparseable:" << req.unparseable << endl;
00067 
00068     StreamJsonPrintingContext printContext(cout);
00069     desc.printJson(&req, printContext);
00070 }
00071 
00072 BOOST_AUTO_TEST_CASE( test_parse_openrtb_sample_requests )
00073 {
00074     for (auto req: samples)
00075         parseBidRequest(req);
00076 }
00077 
00078 void testBidRequest(const std::string & filename)
00079 {
00080     cerr << endl << "loading " << filename << endl;
00081 
00082     ML::Parse_Context context(filename);
00083 
00084     auto res = OpenRtbBidRequestParser::parseBidRequest(context, "test", "test");
00085 
00086     cerr << res->toJson() << endl;
00087 
00088 }
00089 
00090 BOOST_AUTO_TEST_CASE( test_openrtb_sample_requests )
00091 {
00092     for (auto s: samples)
00093         testBidRequest(s);
00094 }
00095 
00096 bool jsonDiff(const Json::Value & v1, const Json::Value & v2,
00097               bool oneOnly = false,
00098               string path = "")
00099 {
00100     bool result = true;
00101 
00102     if (v1.type() != v2.type()) {
00103         cerr << path << ": different types: "
00104              << v1.toString() << " versus "
00105              << v2.toString() << endl;
00106         return false;
00107     }
00108 
00109     switch (v1.type()) {
00110     case Json::arrayValue:
00111         if (v1.size() != v2.size()) {
00112             cerr << path << ": differing lengths: " << v1.size() << " versus "
00113                  << v2.size() << endl;
00114             result = false;
00115             if (oneOnly) return false;
00116         }
00117         for (unsigned i = 0;  i < v1.size();  ++i) {
00118             if (!jsonDiff(v1[i], v2[i], oneOnly,
00119                           path + ML::format("[%d]", i))) {
00120                 result = false;
00121                 if (oneOnly) return false;
00122             }
00123         }
00124         return result;
00125 
00126     case Json::objectValue: {
00127         auto m1 = v1.getMemberNames();
00128         auto m2 = v2.getMemberNames();
00129 
00130         std::sort(m1.begin(), m1.end());
00131         std::sort(m2.begin(), m2.end());
00132 
00133         vector<string> intersection, only1, only2;
00134         std::set_intersection(m1.begin(), m1.end(),
00135                               m2.begin(), m2.end(),
00136                               back_inserter(intersection));
00137         std::set_difference(m1.begin(), m1.end(),
00138                             m2.begin(), m2.end(),
00139                             back_inserter(only1));
00140         std::set_difference(m2.begin(), m2.end(),
00141                             m1.begin(), m1.end(),
00142                             back_inserter(only2));
00143         
00144         if (!only1.empty()) {
00145             cerr << path << ": keys only present in first field: "
00146                  << only1 << endl;
00147             result = false;
00148             if (oneOnly) return false;
00149         }
00150         if (!only2.empty()) {
00151             cerr << path << ": keys only present in second field: "
00152                  << only1 << endl;
00153             result = false;
00154             if (oneOnly) return false;
00155         }
00156 
00157         for (auto f: intersection) {
00158             if (!jsonDiff(v1[f], v2[f], oneOnly, path + "." + f)) {
00159                 result = false;
00160                 if (oneOnly) return false;
00161             }
00162         }
00163         return result;
00164     }
00165 
00166     default:
00167         if (v1.toString() != v2.toString()) {
00168             cerr << path << ": difference: " << v1 << " vs " << v2 << endl;
00169             result = false;
00170             if (oneOnly) return false;
00171         }
00172     }
00173     return result;
00174 }
00175 
00176 void testBidRequestRoundTrip(const std::string & filename,
00177                              const std::string & reqStr)
00178 {
00179     // Take an OpenRTB bid request; convert to Datacratic format;
00180     // serialize that to JSON; reconstitute from JSON back into the
00181     // original format
00182 
00183     static DefaultDescription<OpenRTB::BidRequest> desc;
00184 
00185     OpenRTB::BidRequest req;
00186 
00187     {
00188         StreamingJsonParsingContext context;
00189         context.init(filename, reqStr.c_str(), reqStr.size());
00190         desc.parseJson(&req, context);
00191     }
00192 
00193     string printed;
00194     {
00195         std::ostringstream stream;
00196         StreamJsonPrintingContext printContext(stream);
00197         desc.printJson(&req, printContext);
00198         printed = stream.str();
00199     }
00200 
00201     OpenRTB::BidRequest req2;
00202 
00203     {
00204         StreamingJsonParsingContext context;
00205         context.init(filename, reqStr.c_str(), reqStr.size());
00206         desc.parseJson(&req2, context);
00207     }
00208 
00209     string printed2;
00210     {
00211         std::ostringstream stream;
00212         StreamJsonPrintingContext printContext(stream);
00213         desc.printJson(&req2, printContext);
00214         printed2 = stream.str();
00215     }
00216     
00217     BOOST_CHECK_EQUAL(printed, printed2);
00218 
00219     // Convert to a standard bid request
00220     
00221     std::unique_ptr<BidRequest> br(fromOpenRtb(std::move(req), "openrtb", "openrtb"));
00222     
00223     // Convert it to JSON
00224     string s1 = br->toJsonStr();
00225 
00226     std::unique_ptr<BidRequest> br2(BidRequest::parse("rtbkit", s1));
00227 
00228     string s2 = br2->toJsonStr();
00229     
00230     if (s1 != s2) {
00231         return;
00232         Json::Value j = br->toJson();
00233         Json::Value j2 = br2->toJson();
00234         BOOST_CHECK(jsonDiff(j, j2));
00235     }
00236 }
00237 
00238 BOOST_AUTO_TEST_CASE( test_openrtb_round_trip )
00239 {
00240     vector<string> reqs;
00241 
00242     for (auto s: samples)
00243         reqs.push_back(loadFile(s));
00244 
00245     for (unsigned i = 0;  i < reqs.size();  ++i)
00246         testBidRequestRoundTrip(samples[i], reqs[i]);
00247 }
00248 
00249 BOOST_AUTO_TEST_CASE( benchmark_openrtb_round_trip )
00250 {
00251     vector<string> reqs;
00252 
00253     for (auto s: samples)
00254         reqs.push_back(loadFile(s));
00255 
00256     int done = 0;
00257     
00258     Date before = Date::now();
00259 
00260     for (unsigned i = 0;  i < 1000;  ++i) {
00261         
00262         for (unsigned i = 0;  i < reqs.size();  ++i, ++done)
00263             testBidRequestRoundTrip(samples[i], reqs[i]);
00264     }
00265 
00266     double elapsed = Date::now().secondsSince(before);
00267     
00268     cerr << "did " << done << " in " << elapsed << "s at "
00269          << done / elapsed << "/s" << endl;
00270 }
00271 
00272 BOOST_AUTO_TEST_CASE( benchmark_openrtb_parsing )
00273 {
00274     cerr << "benchmarking OpenRTB parsing" << endl;
00275 
00276     vector<string> reqs;
00277 
00278     for (auto s: samples)
00279         reqs.push_back(loadFile(s));
00280 
00281     int done = 0;
00282     
00283     Date before = Date::now();
00284 
00285     DefaultDescription<OpenRTB::BidRequest> desc;
00286 
00287     for (unsigned i = 0;  i < 1000;  ++i) {
00288         
00289         for (unsigned i = 0;  i < reqs.size();  ++i, ++done) {
00290             
00291             
00292             OpenRTB::BidRequest req;
00293             
00294             {
00295                 StreamingJsonParsingContext context;
00296                 context.init(samples[i], reqs[i].c_str(), reqs[i].size());
00297                 desc.parseJson(&req, context);
00298             }
00299         }
00300     }
00301 
00302     double elapsed = Date::now().secondsSince(before);
00303     
00304     cerr << "did " << done << " in " << elapsed << "s at "
00305          << done / elapsed << "/s" << endl;
00306 }
00307 
00308 BOOST_AUTO_TEST_CASE( benchmark_openrtb_conversion )
00309 {
00310     cerr << "benchmarking OpenRTB parsing and conversion" << endl;
00311 
00312     vector<string> reqs;
00313 
00314     for (auto s: samples)
00315         reqs.push_back(loadFile(s));
00316 
00317     int done = 0;
00318     
00319     Date before = Date::now();
00320 
00321     DefaultDescription<OpenRTB::BidRequest> desc;
00322 
00323     for (unsigned i = 0;  i < 1000;  ++i) {
00324         
00325         for (unsigned i = 0;  i < reqs.size();  ++i, ++done) {
00326             
00327             
00328             OpenRTB::BidRequest req;
00329             
00330             {
00331                 StreamingJsonParsingContext context;
00332                 context.init(samples[i], reqs[i].c_str(), reqs[i].size());
00333                 desc.parseJson(&req, context);
00334             }
00335 
00336             std::unique_ptr<BidRequest> br(fromOpenRtb(std::move(req), "openrtb", "openrtb"));
00337         }
00338     }
00339 
00340     double elapsed = Date::now().secondsSince(before);
00341     
00342     cerr << "did " << done << " in " << elapsed << "s at "
00343          << done / elapsed << "/s" << endl;
00344 }
00345 
00346 BOOST_AUTO_TEST_CASE( benchmark_canonical_parsing )
00347 {
00348     cerr << "benchmarking canonical parsing of OpenRTB-derived bid requests" << endl;
00349 
00350     DefaultDescription<OpenRTB::BidRequest> desc;
00351 
00352     vector<string> reqs;
00353 
00354     for (auto s: samples) {
00355         OpenRTB::BidRequest req;
00356         {
00357             StreamingJsonParsingContext context;
00358             context.init(s);
00359             desc.parseJson(&req, context);
00360         }
00361 
00362         std::unique_ptr<BidRequest> br(fromOpenRtb(std::move(req), "openrtb", "openrtb"));
00363 
00364         reqs.push_back(br->toJsonStr());
00365     }
00366 
00367     int done = 0;
00368     
00369     Date before = Date::now();
00370 
00371     for (unsigned i = 0;  i < 1000;  ++i) {
00372         
00373         for (unsigned i = 0;  i < reqs.size();  ++i, ++done) {
00374             std::unique_ptr<BidRequest> br2(BidRequest::parse("rtbkit", reqs[i]));
00375         }
00376     }
00377 
00378     double elapsed = Date::now().secondsSince(before);
00379     
00380     cerr << "did " << done << " in " << elapsed << "s at "
00381          << done / elapsed << "/s" << endl;
00382 }
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator