diff --git a/README.md b/README.md index 76341197e..7bd45e439 100755 --- a/README.md +++ b/README.md @@ -154,6 +154,8 @@ Please select according to languages: ### V3 changes +* v3.0, 2019-10-30, Cover protocol stack RTMP. 3.0.63 +* v3.0, 2019-10-23, Cover JSON codec. 3.0.62 * v3.0, 2019-10-13, Use http://ossrs.net:8000 as homepage. * v3.0, 2019-10-10, Cover AMF0 codec. 3.0.61 * v3.0, 2019-10-07, [3.0 alpha1(3.0.60)][r3.0a1] released. 107962 lines. diff --git a/trunk/configure b/trunk/configure index e4f75de9b..d5e6b3082 100755 --- a/trunk/configure +++ b/trunk/configure @@ -314,9 +314,8 @@ fi # # utest, the unit-test cases of srs, base on gtest1.6 if [ $SRS_UTEST = YES ]; then - MODULE_FILES=("srs_utest" "srs_utest_amf0" "srs_utest_protocol" - "srs_utest_kernel" "srs_utest_core" "srs_utest_config" - "srs_utest_reload" "srs_utest_service" "srs_utest_app") + MODULE_FILES=("srs_utest" "srs_utest_amf0" "srs_utest_protocol" "srs_utest_kernel" "srs_utest_core" + "srs_utest_config" "srs_utest_protostack" "srs_utest_reload" "srs_utest_service" "srs_utest_app") ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSTRoot} ${LibSSLRoot}) ModuleLibFiles=(${LibSTfile} ${LibSSLfile}) MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE" "APP") diff --git a/trunk/src/core/srs_core.hpp b/trunk/src/core/srs_core.hpp index 5a8617454..8f4e8f406 100644 --- a/trunk/src/core/srs_core.hpp +++ b/trunk/src/core/srs_core.hpp @@ -27,7 +27,7 @@ // The version config. #define VERSION_MAJOR 3 #define VERSION_MINOR 0 -#define VERSION_REVISION 62 +#define VERSION_REVISION 63 // The macros generated by configure script. #include diff --git a/trunk/src/protocol/srs_protocol_json.cpp b/trunk/src/protocol/srs_protocol_json.cpp index a87159fdb..f7bd1c5ed 100644 --- a/trunk/src/protocol/srs_protocol_json.cpp +++ b/trunk/src/protocol/srs_protocol_json.cpp @@ -1632,11 +1632,9 @@ SrsAmf0Any* SrsJsonAny::to_amf0() srs_assert(false); } default: { - break; + return SrsAmf0Any::null(); } } - - return SrsAmf0Any::null(); } SrsJsonAny* SrsJsonAny::str(const char* value) @@ -1729,8 +1727,6 @@ SrsJsonAny* srs_json_parse_tree(json_value* node) default: return NULL; } - - return NULL; } SrsJsonAny* SrsJsonAny::loads(const string& str) @@ -1974,9 +1970,10 @@ SrsJsonAny* SrsJsonArray::at(int index) return elem; } -void SrsJsonArray::add(SrsJsonAny* value) +SrsJsonArray* SrsJsonArray::add(SrsJsonAny* value) { properties.push_back(value); + return this; } SrsJsonArray* SrsJsonArray::append(SrsJsonAny* value) diff --git a/trunk/src/protocol/srs_protocol_json.hpp b/trunk/src/protocol/srs_protocol_json.hpp index 1eedd9b23..0e3d8cab0 100644 --- a/trunk/src/protocol/srs_protocol_json.hpp +++ b/trunk/src/protocol/srs_protocol_json.hpp @@ -156,7 +156,7 @@ public: virtual int count(); // @remark: max index is count(). virtual SrsJsonAny* at(int index); - virtual void add(SrsJsonAny* value); + virtual SrsJsonArray* add(SrsJsonAny* value); // alias to add. virtual SrsJsonArray* append(SrsJsonAny* value); public: diff --git a/trunk/src/utest/srs_utest_amf0.cpp b/trunk/src/utest/srs_utest_amf0.cpp index b42823366..0ca210ab5 100644 --- a/trunk/src/utest/srs_utest_amf0.cpp +++ b/trunk/src/utest/srs_utest_amf0.cpp @@ -2499,6 +2499,11 @@ VOID TEST(ProtocolJSONTest, Interfaces) SrsJsonAny* p = SrsJsonAny::str(); EXPECT_TRUE(p->is_string()); EXPECT_TRUE(p->to_str().empty()); + + SrsAmf0Any* a = p->to_amf0(); + EXPECT_TRUE(a->is_string()); + + srs_freep(a); srs_freep(p); } @@ -2506,6 +2511,11 @@ VOID TEST(ProtocolJSONTest, Interfaces) SrsJsonAny* p = SrsJsonAny::str("hello"); EXPECT_TRUE(p->is_string()); EXPECT_TRUE(string("hello") == p->to_str()); + + SrsAmf0Any* a = p->to_amf0(); + EXPECT_TRUE(a->is_string()); + + srs_freep(a); srs_freep(p); } @@ -2513,6 +2523,44 @@ VOID TEST(ProtocolJSONTest, Interfaces) SrsJsonAny* p = SrsJsonAny::str("hello", 2); EXPECT_TRUE(p->is_string()); EXPECT_TRUE(string("he") == p->to_str()); + + SrsAmf0Any* a = p->to_amf0(); + EXPECT_TRUE(a->is_string()); + + srs_freep(a); + srs_freep(p); + } + + if (true) { + SrsJsonAny* p = SrsJsonAny::boolean(true); + EXPECT_TRUE(p->is_boolean()); + + SrsAmf0Any* a = p->to_amf0(); + EXPECT_TRUE(a->is_boolean()); + + srs_freep(a); + srs_freep(p); + } + + if (true) { + SrsJsonAny* p = SrsJsonAny::integer(); + EXPECT_TRUE(p->is_integer()); + + SrsAmf0Any* a = p->to_amf0(); + EXPECT_TRUE(a->is_number()); + + srs_freep(a); + srs_freep(p); + } + + if (true) { + SrsJsonAny* p = SrsJsonAny::number(); + EXPECT_TRUE(p->is_number()); + + SrsAmf0Any* a = p->to_amf0(); + EXPECT_TRUE(a->is_number()); + + srs_freep(a); srs_freep(p); } } @@ -2573,5 +2621,170 @@ VOID TEST(ProtocolJSONTest, Dumps) EXPECT_STREQ("[]", p->dumps().c_str()); srs_freep(p); } + + if (true) { + SrsJsonObject* p = SrsJsonAny::object(); + p->set("id", SrsJsonAny::integer(3)); + p->set("year", SrsJsonAny::integer(2019)); + EXPECT_STREQ("{\"id\":3,\"year\":2019}", p->dumps().c_str()); + srs_freep(p); + } + + if (true) { + SrsJsonArray* p = SrsJsonAny::array(); + p->add(SrsJsonAny::integer(3)); + p->add(SrsJsonAny::integer(2)); + EXPECT_STREQ("[3,2]", p->dumps().c_str()); + srs_freep(p); + } +} + +VOID TEST(ProtocolJSONTest, Parse) +{ + if (true) { + SrsJsonAny* p = SrsJsonAny::loads("\"hello\""); + EXPECT_TRUE(p->is_string()); + srs_freep(p); + } + + if (true) { + SrsJsonAny* p = SrsJsonAny::loads("true"); + EXPECT_TRUE(p->is_boolean()); + srs_freep(p); + } + + if (true) { + SrsJsonAny* p = SrsJsonAny::loads("3"); + EXPECT_TRUE(p->is_integer()); + srs_freep(p); + } + + if (true) { + SrsJsonAny* p = SrsJsonAny::loads("3.0"); + EXPECT_TRUE(p->is_number()); + srs_freep(p); + } + + if (true) { + SrsJsonAny* p = SrsJsonAny::loads("null"); + EXPECT_TRUE(p->is_null()); + srs_freep(p); + } + + if (true) { + SrsJsonAny* p = SrsJsonAny::loads("{}"); + EXPECT_TRUE(p->is_object()); + srs_freep(p); + } + + if (true) { + SrsJsonAny* p = SrsJsonAny::loads("[]"); + EXPECT_TRUE(p->is_array()); + srs_freep(p); + } + + if (true) { + SrsJsonAny* p = SrsJsonAny::loads("{\"id\":3}"); + EXPECT_TRUE(p->is_object()); + srs_freep(p); + } + + if (true) { + SrsJsonAny* p = SrsJsonAny::loads("[\"id\",3]"); + EXPECT_TRUE(p->is_array()); + srs_freep(p); + } +} + +VOID TEST(ProtocolJSONTest, ObjectAPI) +{ + SrsJsonObject* p = SrsJsonAny::object(); + SrsAutoFree(SrsJsonObject, p); + + p->set("id", SrsJsonAny::integer(3)); + p->set("name", SrsJsonAny::str("srs")); + + EXPECT_STREQ("name", p->key_at(1).c_str()); + EXPECT_STREQ("srs", p->value_at(1)->to_str().c_str()); + + p->set("name", NULL); + p->set("name", SrsJsonAny::str("ossrs")); + p->set("version", SrsJsonAny::number(3.1)); + p->set("stable", SrsJsonAny::boolean(true)); + + SrsJsonObject* pp = SrsJsonAny::object(); + p->set("args", pp); + pp->set("url", SrsJsonAny::str("ossrs.net")); + pp->set("year", SrsJsonAny::integer(2019)); + + SrsJsonArray* pa = SrsJsonAny::array(); + p->set("authors", pa); + pa->add(SrsJsonAny::str("winlin")); + pa->add(SrsJsonAny::str("wenjie")); + + SrsJsonAny* prop = p->get_property("name"); + EXPECT_STREQ("ossrs", prop->to_str().c_str()); + EXPECT_STREQ("ossrs", p->ensure_property_string("name")->to_str().c_str()); + + EXPECT_TRUE(NULL == p->get_property("invalid")); + EXPECT_TRUE(NULL == p->ensure_property_string("invalid")); + EXPECT_TRUE(NULL == p->ensure_property_string("id")); + + EXPECT_TRUE(NULL == p->ensure_property_integer("invalid")); + EXPECT_TRUE(NULL == p->ensure_property_integer("name")); + EXPECT_EQ(3, p->ensure_property_integer("id")->to_integer()); + + EXPECT_TRUE(NULL == p->ensure_property_number("invalid")); + EXPECT_TRUE(NULL == p->ensure_property_number("name")); + EXPECT_EQ(3.1, p->ensure_property_number("version")->to_number()); + + EXPECT_TRUE(NULL == p->ensure_property_boolean("invalid")); + EXPECT_TRUE(NULL == p->ensure_property_boolean("name")); + EXPECT_TRUE(p->ensure_property_boolean("stable")->to_boolean()); + + EXPECT_TRUE(NULL == p->ensure_property_object("invalid")); + EXPECT_TRUE(NULL == p->ensure_property_object("name")); + EXPECT_TRUE(NULL != p->ensure_property_object("args")->to_object()); + + EXPECT_TRUE(NULL == p->ensure_property_array("invalid")); + EXPECT_TRUE(NULL == p->ensure_property_array("name")); + EXPECT_TRUE(NULL != p->ensure_property_array("authors")->to_array()); + + SrsAmf0Object* a = (SrsAmf0Object*)p->to_amf0(); + EXPECT_EQ(6, a->count()); + srs_freep(a); +} + +VOID TEST(ProtocolJSONTest, ArrayAPI) +{ + SrsJsonArray* p = SrsJsonAny::array(); + SrsAutoFree(SrsJsonArray, p); + + p->add(SrsJsonAny::integer(2019)); + p->add(SrsJsonAny::str("srs")); + p->add(SrsJsonAny::boolean(true)); + + EXPECT_STREQ("srs", p->at(1)->to_str().c_str()); + + SrsAmf0StrictArray* a = (SrsAmf0StrictArray*)p->to_amf0(); + EXPECT_EQ(3, a->count()); + srs_freep(a); +} + +VOID TEST(ProtocolJSONTest, ParseSpecial) +{ + if (true) { + SrsJsonAny* p = SrsJsonAny::loads("[\"hello\"\r\n, 2019]"); + EXPECT_TRUE(p->is_array()); + EXPECT_EQ(2, p->to_array()->count()); + srs_freep(p); + } + + if (true) { + SrsJsonAny* p = SrsJsonAny::loads("[\"hello\"\r\n, 2019, \"\\xe6\\xb5\\x81\"]"); + EXPECT_TRUE(p->is_array()); + EXPECT_EQ(3, p->to_array()->count()); + srs_freep(p); + } } diff --git a/trunk/src/utest/srs_utest_protostack.cpp b/trunk/src/utest/srs_utest_protostack.cpp new file mode 100644 index 000000000..3c26e3452 --- /dev/null +++ b/trunk/src/utest/srs_utest_protostack.cpp @@ -0,0 +1,151 @@ +/* +The MIT License (MIT) + +Copyright (c) 2013-2019 Winlin + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +class MockErrorPacket : public SrsPacket +{ +protected: + virtual int get_size() { + return 1024; + } +}; + +VOID TEST(ProtoStackTest, PacketEncode) +{ + srs_error_t err; + + int size; + char* payload; + + if (true) { + MockErrorPacket pkt; + HELPER_EXPECT_FAILED(pkt.encode(size, payload)); + } + + if (true) { + MockErrorPacket pkt; + SrsBuffer b; + HELPER_EXPECT_FAILED(pkt.decode(&b)); + } + + if (true) { + SrsPacket pkt; + EXPECT_EQ(0, pkt.get_prefer_cid()); + EXPECT_EQ(0, pkt.get_message_type()); + EXPECT_EQ(0, pkt.get_size()); + } + + if (true) { + MockErrorPacket pkt; + EXPECT_EQ(1024, pkt.get_size()); + } +} + +VOID TEST(ProtoStackTest, ManualFlush) +{ + srs_error_t err; + + if (true) { + MockBufferIO io; + SrsProtocol p(&io); + + // Always response ACK message. + HELPER_EXPECT_SUCCESS(p.set_in_window_ack_size(1)); + + // Default is auto response. + HELPER_EXPECT_SUCCESS(p.response_acknowledgement_message()); + EXPECT_EQ(12+4, io.out_buffer.length()); + } + + if (true) { + MockBufferIO io; + SrsProtocol p(&io); + + // Always response ACK message. + HELPER_EXPECT_SUCCESS(p.set_in_window_ack_size(1)); + + p.set_auto_response(true); + HELPER_EXPECT_SUCCESS(p.response_acknowledgement_message()); + EXPECT_EQ(12+4, io.out_buffer.length()); + } + + if (true) { + MockBufferIO io; + SrsProtocol p(&io); + + // Always response ACK message. + HELPER_EXPECT_SUCCESS(p.set_in_window_ack_size(1)); + + // When not auto response, need to flush it manually. + p.set_auto_response(false); + HELPER_EXPECT_SUCCESS(p.response_acknowledgement_message()); + EXPECT_EQ(0, io.out_buffer.length()); + + HELPER_EXPECT_SUCCESS(p.manual_response_flush()); + EXPECT_EQ(12+4, io.out_buffer.length()); + } + + if (true) { + MockBufferIO io; + SrsProtocol p(&io); + + // Always response ACK message. + HELPER_EXPECT_SUCCESS(p.set_in_window_ack_size(1)); + + HELPER_EXPECT_SUCCESS(p.response_ping_message(1024)); + EXPECT_EQ(12+6, io.out_buffer.length()); + } + + if (true) { + MockBufferIO io; + SrsProtocol p(&io); + + // Always response ACK message. + HELPER_EXPECT_SUCCESS(p.set_in_window_ack_size(1)); + + // When not auto response, need to flush it manually. + p.set_auto_response(false); + HELPER_EXPECT_SUCCESS(p.response_ping_message(1024)); + EXPECT_EQ(0, io.out_buffer.length()); + + HELPER_EXPECT_SUCCESS(p.manual_response_flush()); + EXPECT_EQ(12+6, io.out_buffer.length()); + } +} + diff --git a/trunk/src/utest/srs_utest_protostack.hpp b/trunk/src/utest/srs_utest_protostack.hpp new file mode 100644 index 000000000..9f222d46a --- /dev/null +++ b/trunk/src/utest/srs_utest_protostack.hpp @@ -0,0 +1,45 @@ +/* +The MIT License (MIT) + +Copyright (c) 2013-2019 Winlin + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef SRS_UTEST_PROTO_STACK_HPP +#define SRS_UTEST_PROTO_STACK_HPP + +/* +#include +*/ +#include + +#include +#include + +#include +#include +#include +#include + +using namespace _srs_internal; + +#include + +#endif +