Skip to content

Commit

Permalink
Build-To-Use: 3.2.0-74
Browse files Browse the repository at this point in the history
CBL-4721: UnicodeCollator_Stub.cc fails when building couchbase-mobile-tools/logcat on ubuntu. (#1839)
CBL-127:  Conflict error in CBL P2P push replication when using different target database UID (#1838)
CBL-4530: Remove unused actor::Observer and actor::Property (#1835)
CBL-4638: Decoded timestamps appear incorrect (#1832)
  • Loading branch information
jianminzhao committed Jul 17, 2023
2 parents 141d8a3 + 1604640 commit 2fc5ecb
Show file tree
Hide file tree
Showing 18 changed files with 415 additions and 138 deletions.
4 changes: 3 additions & 1 deletion .github/workflows/xcodebuild.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ on:
env:
# Customize the Xcode configuration here (Release or Debug)
# NOTE: If we decide to archive the build products we should build with RelWithDebInfo instead.
# Test_CE is a dupplicate of Debug except it has the c++ define, LITECORE_CPPTEST, activated.
CONFIGURATION: Debug
CONFIGURATION_CPP: Test_CE

jobs:
build:
Expand All @@ -40,7 +42,7 @@ jobs:
project: Xcode/LiteCore.xcodeproj
scheme: LiteCore C++ Tests
destination: platform=macOS
configuration: $CONFIGURATION
configuration: $CONFIGURATION_CPP
action: build

- name: "Build C4Tests"
Expand Down
4 changes: 2 additions & 2 deletions LiteCore/Storage/Record.hh
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ namespace litecore {
// Leave _body alone if the new body is identical; this prevents a doc's body from
// being swapped out when clients are using Fleece values pointing into it.
if ( slice(body) != _body || !_body ) {
_body = move(body);
_body = std::move(body);
_bodySize = _body.size;
}
}
Expand All @@ -109,7 +109,7 @@ namespace litecore {
void setExtra(SLICE extra) {
// Same thing as setBody: there may be Fleece objects (other revs) in _extra.
if ( slice(extra) != _extra || !_extra ) {
_extra = move(extra);
_extra = std::move(extra);
_extraSize = _extra.size;
}
}
Expand Down
8 changes: 6 additions & 2 deletions LiteCore/Storage/UnicodeCollator_Stub.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,13 @@ namespace litecore {

using namespace std;

int CompareUTF8(slice str1, slice str2, const CollationContext&) { error::_throw(error::Unimplemented); }
int CompareUTF8(fleece::slice str1, fleece::slice str2, const CollationContext&) {
error::_throw(error::Unimplemented);
}

bool ContainsUTF8(slice str, slice substr, const CollationContext&) { error::_throw(error::Unimplemented); }
bool ContainsUTF8(fleece::slice str, fleece::slice substr, const CollationContext&) {
error::_throw(error::Unimplemented);
}

unique_ptr<CollationContext> RegisterSQLiteUnicodeCollation(sqlite3* dbHandle, const Collation& coll) {
return nullptr;
Expand Down
33 changes: 0 additions & 33 deletions LiteCore/Support/ActorProperty.cc

This file was deleted.

77 changes: 0 additions & 77 deletions LiteCore/Support/ActorProperty.hh

This file was deleted.

2 changes: 1 addition & 1 deletion LiteCore/Support/Batcher.hh
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ namespace litecore::actor {
if ( gen < _generation ) return {};
_scheduled = false;
++_generation;
return move(_items);
return std::move(_items);
}

private:
Expand Down
22 changes: 12 additions & 10 deletions LiteCore/Support/LogDecoder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,15 @@ namespace litecore {
return {secs, microsecs};
}

void LogIterator::writeTimestamp(Timestamp t, ostream& out) {
void LogIterator::writeTimestamp(Timestamp t, ostream& out, bool inUtcTime) {
local_time<microseconds> tp{seconds(t.secs) + microseconds(t.microsecs)};
struct tm tmpTime = FromTimestamp(duration_cast<seconds>(tp.time_since_epoch()));
tp -= GetLocalTZOffset(&tmpTime, true);
out << format("%T| ", tp);
const char* fmt = "%TZ| ";
if ( !inUtcTime ) {
struct tm tmpTime = FromTimestamp(duration_cast<seconds>(tp.time_since_epoch()));
tp += GetLocalTZOffset(&tmpTime, true);
fmt = "%T| ";
}
out << format(fmt, tp);
}

void LogIterator::writeISO8601DateTime(Timestamp t, std::ostream& out) {
Expand All @@ -66,7 +70,7 @@ namespace litecore {
string LogIterator::formatDate(Timestamp t) {
local_time<microseconds> tp(seconds(t.secs) + microseconds(t.microsecs));
struct tm tmpTime = FromTimestamp(duration_cast<seconds>(tp.time_since_epoch()));
tp -= GetLocalTZOffset(&tmpTime, true);
tp += GetLocalTZOffset(&tmpTime, true);
stringstream out;
out << format("%c", tp);
return out.str();
Expand All @@ -91,7 +95,7 @@ namespace litecore {
while ( next() ) {
auto ts = timestamp();
if ( start && ts < *start ) continue;
writeTimestamp(ts, out);
writeTimestamp(ts, out, true);

string levelName;
if ( level() >= 0 && level() < levelNames.size() ) levelName = levelNames[level()];
Expand Down Expand Up @@ -149,11 +153,9 @@ namespace litecore {
void LogDecoder::decodeTo(ostream& out, const std::vector<std::string>& levelNames,
std::optional<Timestamp> startingAt) {
if ( !startingAt || *startingAt < Timestamp{_startTime, 0} ) {
writeTimestamp({_startTime, 0}, out);
writeTimestamp({_startTime, 0}, out, true);
local_time<seconds> tp{seconds(_startTime)};
struct tm tmpTime = FromTimestamp(duration_cast<seconds>(tp.time_since_epoch()));
tp -= GetLocalTZOffset(&tmpTime, true);
out << "---- Logging begins on " << format("%A, %x", tp) << " ----" << endl;
out << "---- Logging begins on " << format("%A %FT%TZ", tp) << " ----" << endl;
}

LogIterator::decodeTo(out, levelNames, startingAt);
Expand Down
2 changes: 1 addition & 1 deletion LiteCore/Support/LogDecoder.hh
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ namespace litecore {
static Timestamp now();
static std::string formatDate(Timestamp);
static void writeISO8601DateTime(Timestamp, std::ostream&);
static void writeTimestamp(Timestamp, std::ostream&);
static void writeTimestamp(Timestamp, std::ostream&, bool inUtcTime = false);
static void writeHeader(const std::string& levelName, const std::string& domainName, std::ostream&);
};

Expand Down
3 changes: 3 additions & 0 deletions LiteCore/Support/Logging.cc
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ namespace litecore {
<< CBL_LOG_EXTENSION;
return ss.str();
}
#ifdef LITECORE_CPPTEST
string createLogPath_forUnitTest(LogLevel level) { return createLogPath(level); }
#endif

static void setupFileOut() {
for ( int i = 0; kLevelNames[i]; i++ ) {
Expand Down
3 changes: 3 additions & 0 deletions LiteCore/Support/Logging.hh
Original file line number Diff line number Diff line change
Expand Up @@ -271,4 +271,7 @@ namespace litecore {

mutable unsigned _objectRef{0};
};
#ifdef LITECORE_CPPTEST
std::string createLogPath_forUnitTest(LogLevel level);
#endif
} // namespace litecore
38 changes: 36 additions & 2 deletions LiteCore/tests/LogEncoderTest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,17 @@
#include "LogDecoder.hh"
#include "LiteCoreTest.hh"
#include "StringUtil.hh"
#include "ParseDate.hh"
#include "fleece/PlatformCompat.hh"
#include <regex>
#include <sstream>
#include <fstream>

using namespace std;

#define DATESTAMP "\\w+, \\d{2}/\\d{2}/\\d{2}"
#define TIMESTAMP "\\d{2}:\\d{2}:\\d{2}\\.\\d{6}\\| "
// These formats are used in the decoded log files. They are UTC times.
#define DATESTAMP "\\w+ \\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z"
#define TIMESTAMP "\\d{2}:\\d{2}:\\d{2}\\.\\d{6}Z\\| "

constexpr size_t kFolderBufSize = 64;

Expand Down Expand Up @@ -55,6 +57,10 @@ static string dumpLog(const string& encoded, const vector<string>& levelNames) {
}

TEST_CASE("LogEncoder formatting", "[Log]") {
// For checking the timestamp in the path to the binary log file.
#ifdef LITECORE_CPPTEST
string logPath = litecore::createLogPath_forUnitTest(LogLevel::Info);
#endif
stringstream out;
{
LogEncoder logger(out, LogLevel::Info);
Expand Down Expand Up @@ -84,6 +90,34 @@ TEST_CASE("LogEncoder formatting", "[Log]") {
"Int 1234567890, Long 234567890, LongLong 123456789123456789, Size 1234567890, Char @\\n" TIMESTAMP
"String is 'C string', slice is 'hello' \\(hex 68656c6c6f\\)\\n");
CHECK(regex_match(result, expected));

#ifdef LITECORE_CPPTEST
// We insert timestamp in milliseconds (w.r.t. UTC) in the path to the binary log files.
// We also add the timestamp inside the log. When decoded to string, it is
// represented as UTC time, like, "Monday 2023-07-03T19:25:01Z"
// We want to ensure they are consistent.
regex catchUTCTimeTag{"^" TIMESTAMP "---- Logging begins on (" DATESTAMP ")"};
smatch m;
REQUIRE(regex_search(result, m, catchUTCTimeTag));
CHECK(m.size() == 2);
string utcTimeTag = m[1].str();
// Remove the weekday name
REQUIRE(regex_search(utcTimeTag, m, regex{"[^0-9]*"}));
string utctime = m.suffix().str();
auto utctimestampInLog = fleece::ParseISO8601Date(slice(utctime));
// From milliseconds to seconds
utctimestampInLog /= 1000;

REQUIRE(regex_search(logPath, m, regex{"cbl_info_([0-9]*)\\.cbllog$"}));
string timestampOnLogFilePath = m[1].str();
// chomp it to seconds
REQUIRE(timestampOnLogFilePath.length() > 3);
timestampOnLogFilePath = timestampOnLogFilePath.substr(0, timestampOnLogFilePath.length() - 3);

stringstream ss;
ss << utctimestampInLog;
CHECK(ss.str() == timestampOnLogFilePath);
#endif
}

TEST_CASE("LogEncoder levels/domains", "[Log]") {
Expand Down
1 change: 0 additions & 1 deletion Networking/BLIP/cmake/platform_base.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ function(set_source_files_base)
${WEBSOCKETS_LOCATION}/WebSocketImpl.cc
${WEBSOCKETS_LOCATION}/WebSocketInterface.cc
${SUPPORT_LOCATION}/Actor.cc
${SUPPORT_LOCATION}/ActorProperty.cc
# ${SUPPORT_LOCATION}/Async.cc
${SUPPORT_LOCATION}/Channel.cc
${SUPPORT_LOCATION}/Codec.cc
Expand Down
48 changes: 47 additions & 1 deletion Replicator/tests/ReplicatorLoopbackTest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1928,6 +1928,7 @@ TEST_CASE_METHOD(ReplicatorLoopbackTest, "Replicate Encrypted Properties", "[Pus
CHECK(clear == "\"123-45-6789\"");
}
}
#endif // COUCHBASE_ENTERPRISE

TEST_CASE_METHOD(ReplicatorLoopbackTest, "Replication Collections Must Match", "[Push][Pull][Sync]") {
Options opts = GENERATE_COPY(Options::pushing(kC4OneShot, _collSpec), Options::pulling(kC4OneShot, _collSpec),
Expand Down Expand Up @@ -1956,4 +1957,49 @@ TEST_CASE_METHOD(ReplicatorLoopbackTest, "Replication Collections Must Match", "
runReplicators(opts, serverOpts);
}

#endif // COUCHBASE_ENTERPRISE
TEST_CASE_METHOD(ReplicatorLoopbackTest, "Conflict Includes Rev", "[Push][Sync]") {
// The new push property, "conflictIncludesRev", introduced by the resolution of CBL-2637,
// also fixed the scenrio of CBL-127.

FLSlice docID = C4STR("doc");
slice jBody = R"({"name":"otherDB"})"_sl;
auto revID = createFleeceRev(_collDB2, docID, nullslice, jBody);

_expectedDocumentCount = 1;
// Pre-conditions: db is empty, db2 has one doc.
runPushPullReplication();

// Post-conditions: db and db2 are sync'ed.
c4::ref<C4Document> docInDb1 = c4coll_getDoc(_collDB1, docID, true, kDocGetAll, nullptr);
c4::ref<C4Document> docInDb2 = c4coll_getDoc(_collDB2, docID, true, kDocGetAll, nullptr);
string revInDb1{(char*)docInDb1->revID.buf, docInDb1->revID.size};
string revInDb2{(char*)docInDb2->revID.buf, docInDb2->revID.size};
REQUIRE(revInDb1 == revInDb2);
REQUIRE(revID == revInDb1);
REQUIRE(c4rev_getGeneration(slice(revID)) == 1);

// Modify the document in db
slice modifiedBody = R"({"name":"otherDB","modified":1})"_sl;
auto revID_2 = createFleeceRev(_collDB1, docID, nullslice, modifiedBody);

Replicator::Options serverOpts = Replicator::Options::passive(_collSpec);
Replicator::Options clientOpts = Replicator::Options::pushing(kC4OneShot, _collSpec);

SECTION("Same Target Revision 1 Was Synced") {}
SECTION("Assign a New UID to the Target") {
// We are to push revision 2 but with different UID, the pusher lost track of the
// remote counterpart of revision 1. The property "conflictIncludesRev" attached to the
// "proposeChange" message helps to resolve it.
clientOpts.setProperty(kC4ReplicatorOptionRemoteDBUniqueID, "DifferentUID"_sl);
}

_expectedDocumentCount = 1;
runReplicators(clientOpts, serverOpts);
docInDb1 = c4coll_getDoc(_collDB1, docID, true, kDocGetAll, nullptr);
docInDb2 = c4coll_getDoc(_collDB2, docID, true, kDocGetAll, nullptr);
revInDb1 = string{(char*)docInDb1->revID.buf, docInDb1->revID.size};
revInDb2 = string{(char*)docInDb2->revID.buf, docInDb2->revID.size};
CHECK(revInDb1 == revInDb2);
CHECK(revID_2 == revInDb1);
CHECK(c4rev_getGeneration(slice(revID_2)) == 2);
}
Loading

0 comments on commit 2fc5ecb

Please sign in to comment.