File
Blob: src/workerd/server/actor-id-impl-test.c++
| 1 | // Copyright (c) 2024-2029 Cloudflare, Inc. |
| 2 | // Licensed under the Apache 2.0 license found in the LICENSE file or at: |
| 3 | // https://opensource.org/licenses/Apache-2.0 |
| 4 | |
| 5 | #include <workerd/jsg/exception.h> |
| 6 | #include <workerd/server/actor-id-impl.h> |
| 7 | |
| 8 | #include <openssl/hmac.h> |
| 9 | |
| 10 | #include <kj/debug.h> |
| 11 | #include <kj/encoding.h> |
| 12 | #include <kj/test.h> |
| 13 | |
| 14 | constexpr kj::byte zero32[SHA256_DIGEST_LENGTH] = {0}; |
| 15 | |
| 16 | KJ_TEST("ActorIdImpl equals test") { |
| 17 | using ActorIdImpl = workerd::server::ActorIdFactoryImpl::ActorIdImpl; |
| 18 | struct ActorEqualsTest { |
| 19 | ActorIdImpl actorLeft = {zero32, kj::none}; |
| 20 | ActorIdImpl actorRight = {zero32, kj::none}; |
| 21 | bool expectedResult; |
| 22 | ActorEqualsTest(kj::byte leftFill, |
| 23 | const char* leftString, |
| 24 | kj::byte rightFill, |
| 25 | const char* rightString, |
| 26 | bool expectedResult) |
| 27 | : expectedResult(expectedResult) { |
| 28 | kj::byte idParamCopier[SHA256_DIGEST_LENGTH] = {0}; |
| 29 | memset(idParamCopier, leftFill, SHA256_DIGEST_LENGTH); |
| 30 | if (leftString == nullptr) { |
| 31 | actorLeft = ActorIdImpl(idParamCopier, kj::none); |
| 32 | } else { |
| 33 | actorLeft = ActorIdImpl(idParamCopier, kj::heapString(leftString)); |
| 34 | } |
| 35 | memset(idParamCopier, rightFill, SHA256_DIGEST_LENGTH); |
| 36 | if (rightString == nullptr) { |
| 37 | actorRight = ActorIdImpl(idParamCopier, kj::none); |
| 38 | } else { |
| 39 | actorRight = ActorIdImpl(idParamCopier, kj::heapString(rightString)); |
| 40 | } |
| 41 | } |
| 42 | }; |
| 43 | using Test = ActorEqualsTest; |
| 44 | Test testCases[] = { |
| 45 | {0, nullptr, 0, nullptr, true}, |
| 46 | {0, nullptr, 1, nullptr, false}, |
| 47 | {0, "hello", 0, "goodbye", true}, |
| 48 | {0, "hello", 1, "goodbye", false}, |
| 49 | {0, "hello", 0, nullptr, true}, |
| 50 | {0, "hello", 1, nullptr, false}, |
| 51 | }; |
| 52 | for (const auto& testCase: testCases) { |
| 53 | KJ_EXPECT(testCase.actorLeft.equals(testCase.actorRight) == testCase.expectedResult); |
| 54 | } |
| 55 | } |
| 56 | |
| 57 | constexpr size_t BASE_LENGTH = SHA256_DIGEST_LENGTH / 2; |
| 58 | kj::String computeProperTestMac(const char* strId, const char* strKey) { |
| 59 | auto id = kj::decodeHex(kj::heapString(strId)); |
| 60 | KJ_ASSERT(!id.hadErrors); |
| 61 | KJ_ASSERT(id.size() == SHA256_DIGEST_LENGTH); |
| 62 | kj::byte key[SHA256_DIGEST_LENGTH] = {0}; |
| 63 | auto stringPtrKey = kj::StringPtr(strKey); |
| 64 | SHA256(stringPtrKey.asBytes().begin(), stringPtrKey.size(), key); |
| 65 | kj::byte hmacOut[SHA256_DIGEST_LENGTH] = {0}; |
| 66 | unsigned int len = SHA256_DIGEST_LENGTH; |
| 67 | HMAC(EVP_sha256(), key, sizeof(key), id.begin(), BASE_LENGTH, hmacOut, &len); |
| 68 | KJ_ASSERT(len == SHA256_DIGEST_LENGTH); |
| 69 | auto ret = kj::heapArray<kj::byte>(SHA256_DIGEST_LENGTH); |
| 70 | memcpy(ret.begin(), id.begin(), BASE_LENGTH); |
| 71 | memcpy(ret.begin() + BASE_LENGTH, hmacOut, SHA256_DIGEST_LENGTH - BASE_LENGTH); |
| 72 | return kj::encodeHex(ret); |
| 73 | } |
| 74 | |
| 75 | constexpr const char deadbeef64[] = |
| 76 | "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"; |
| 77 | KJ_TEST("ActorIdImplFactory idFromString test") { |
| 78 | using ActorIdFactoryImpl = workerd::server::ActorIdFactoryImpl; |
| 79 | struct ActorFactoryFromStringTest { |
| 80 | ActorIdFactoryImpl actor; |
| 81 | kj::String string; |
| 82 | bool isFatal; |
| 83 | ActorFactoryFromStringTest(const char* actorString, const char* string, bool isFatal) |
| 84 | : actor(actorString), |
| 85 | string(kj::heapString(string)), |
| 86 | isFatal(isFatal) {} |
| 87 | ActorFactoryFromStringTest(const char* actorString, kj::String string, bool isFatal) |
| 88 | : actor(actorString), |
| 89 | string(kj::mv(string)), |
| 90 | isFatal(isFatal) {} |
| 91 | }; |
| 92 | using Test = ActorFactoryFromStringTest; |
| 93 | Test testCases[] = { |
| 94 | {"hello", "goodbye", true}, // a random string of the wrong length |
| 95 | {"hello", deadbeef64, true}, //Gets past the first assert |
| 96 | {deadbeef64, computeProperTestMac(deadbeef64, deadbeef64), |
| 97 | false}, //Gets past the second assert |
| 98 | }; |
| 99 | for (auto& testCase: testCases) { |
| 100 | if (testCase.isFatal) { |
| 101 | KJ_EXPECT_THROW(FAILED, testCase.actor.idFromString(kj::heapString(testCase.string))); |
| 102 | } else { |
| 103 | auto result = testCase.actor.idFromString(kj::heapString(testCase.string)); |
| 104 | KJ_EXPECT(result->getName() == kj::none); |
| 105 | } |
| 106 | } |
| 107 | } |