Skip to content
File

Blob: src/workerd/server/actor-id-impl-test.c++

4.0 KB
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 
14constexpr kj::byte zero32[SHA256_DIGEST_LENGTH] = {0};
15 
16KJ_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 
57constexpr size_t BASE_LENGTH = SHA256_DIGEST_LENGTH / 2;
58kj::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 
75constexpr const char deadbeef64[] =
76 "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef";
77KJ_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}