From c7d192996afbb64d20471a1d74920a895750808f Mon Sep 17 00:00:00 2001 From: YuLuo Date: Sat, 6 Jul 2024 22:55:58 +0800 Subject: [PATCH 1/7] [Improve] add MapCap & LruMap unit test (#2227) Signed-off-by: yuluo-yx Co-authored-by: tomsun28 --- .../hertzbeat/common/util/LruHashMapTest.java | 50 ++++++++++++++++++- .../hertzbeat/common/util/MapCapUtilTest.java | 44 ++++++++++++++++ 2 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 common/src/test/java/org/apache/hertzbeat/common/util/MapCapUtilTest.java diff --git a/common/src/test/java/org/apache/hertzbeat/common/util/LruHashMapTest.java b/common/src/test/java/org/apache/hertzbeat/common/util/LruHashMapTest.java index 8890f7401c4..73a4642d8a4 100644 --- a/common/src/test/java/org/apache/hertzbeat/common/util/LruHashMapTest.java +++ b/common/src/test/java/org/apache/hertzbeat/common/util/LruHashMapTest.java @@ -19,12 +19,60 @@ import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + /** * Test case for {@link LruHashMap} */ class LruHashMapTest { @Test - void removeEldestEntry() { + void testLruHashMap() { + + int initThreshold = 3; + LruHashMap initLruMap = new LruHashMap<>(initThreshold); + assertNotNull(initLruMap); + assertEquals(0, initLruMap.size()); + + int putAndGetThreshold = 2; + LruHashMap putAndGetLruMap = new LruHashMap<>(putAndGetThreshold); + + putAndGetLruMap.put(1, "one"); + putAndGetLruMap.put(2, "two"); + + // Both entries should be present + assertEquals("one", putAndGetLruMap.get(1)); + assertEquals("two", putAndGetLruMap.get(2)); + + int evictionThreshold = 2; + LruHashMap evictionLruMap = new LruHashMap<>(evictionThreshold); + + evictionLruMap.put(1, "one"); + evictionLruMap.put(2, "two"); + evictionLruMap.put(3, "three"); + + // The least recently used entry (1, "one") should be evicted + assertNull(evictionLruMap.get(1)); + assertEquals("two", evictionLruMap.get(2)); + assertEquals("three", evictionLruMap.get(3)); + + int accessOrderThreshold = 2; + LruHashMap accessOrderLruMap = new LruHashMap<>(accessOrderThreshold); + + accessOrderLruMap.put(1, "one"); + accessOrderLruMap.put(2, "two"); + + // Access the first entry to make it recently used + accessOrderLruMap.get(1); + + accessOrderLruMap.put(3, "three"); + + // The least recently used entry (2, "two") should be evicted + assertEquals("one", accessOrderLruMap.get(1)); + assertNull(accessOrderLruMap.get(2)); + assertEquals("three", accessOrderLruMap.get(3)); } + } diff --git a/common/src/test/java/org/apache/hertzbeat/common/util/MapCapUtilTest.java b/common/src/test/java/org/apache/hertzbeat/common/util/MapCapUtilTest.java new file mode 100644 index 00000000000..fac11a9cdf0 --- /dev/null +++ b/common/src/test/java/org/apache/hertzbeat/common/util/MapCapUtilTest.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hertzbeat.common.util; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Test for {@link MapCapUtil} + */ +class MapCapUtilTest { + + @Test + public void testCalInitMap() { + int size = 0; + int expectedCapacity = (int) Math.ceil(size / 0.75); + int actualCapacity = MapCapUtil.calInitMap(size); + + assertEquals(expectedCapacity, actualCapacity); + + size = 10; + expectedCapacity = (int) Math.ceil(size / 0.75); + actualCapacity = MapCapUtil.calInitMap(size); + + assertEquals(expectedCapacity, actualCapacity); + } + +} From 21a77885226aafdf7b4b3afe94704174d93fd8a7 Mon Sep 17 00:00:00 2001 From: YuLuo Date: Sat, 6 Jul 2024 23:23:36 +0800 Subject: [PATCH 2/7] [Improve] add ProtoJsonUtil unit test (#2228) Signed-off-by: yuluo-yx Co-authored-by: tomsun28 --- .../hertzbeat/common/util/ProtoJsonUtil.java | 13 + .../common/util/ProtoJsonUtilTest.java | 38 +- .../common/util/entity/PersonTest.java | 837 ++++++++++++++++++ common/src/test/proto/person.proto | 28 + 4 files changed, 915 insertions(+), 1 deletion(-) create mode 100644 common/src/test/java/org/apache/hertzbeat/common/util/entity/PersonTest.java create mode 100644 common/src/test/proto/person.proto diff --git a/common/src/main/java/org/apache/hertzbeat/common/util/ProtoJsonUtil.java b/common/src/main/java/org/apache/hertzbeat/common/util/ProtoJsonUtil.java index a7e71a2944e..e3d68b62527 100644 --- a/common/src/main/java/org/apache/hertzbeat/common/util/ProtoJsonUtil.java +++ b/common/src/main/java/org/apache/hertzbeat/common/util/ProtoJsonUtil.java @@ -19,6 +19,7 @@ import com.google.protobuf.Message; import com.google.protobuf.util.JsonFormat; +import java.util.Objects; import lombok.extern.slf4j.Slf4j; /** @@ -39,6 +40,12 @@ private ProtoJsonUtil() { * @return json */ public static String toJsonStr(Message proto) { + + if (Objects.isNull(proto)) { + log.error("proto is null"); + return null; + } + try { return PRINTER.print(proto); } catch (Exception e) { @@ -54,6 +61,12 @@ public static String toJsonStr(Message proto) { * @return protobuf */ public static Message toProtobuf(String json, Message.Builder builder) { + + if (Objects.isNull(json) || Objects.isNull(builder)) { + log.error("json or builder is null"); + return null; + } + try { PARSER.merge(json, builder); return builder.build(); diff --git a/common/src/test/java/org/apache/hertzbeat/common/util/ProtoJsonUtilTest.java b/common/src/test/java/org/apache/hertzbeat/common/util/ProtoJsonUtilTest.java index d1c6688e383..394f9bbd958 100644 --- a/common/src/test/java/org/apache/hertzbeat/common/util/ProtoJsonUtilTest.java +++ b/common/src/test/java/org/apache/hertzbeat/common/util/ProtoJsonUtilTest.java @@ -17,23 +17,59 @@ package org.apache.hertzbeat.common.util; +import org.apache.hertzbeat.common.util.entity.PersonTest.Person; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.util.JsonFormat; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + /** * Test case for {@link ProtoJsonUtil} */ class ProtoJsonUtilTest { + private Person samplePerson; + private String sampleJson; + @BeforeEach void setUp() { + + samplePerson = Person.newBuilder() + .setName("John Doe") + .setId(123) + .setEmail("john.doe@example.com") + .build(); + + sampleJson = "{ \"name\": \"John Doe\", \"id\": 123, \"email\": \"john.doe@example.com\" }"; } @Test - void toJsonStr() { + void toJsonStr() throws InvalidProtocolBufferException { + + String json = ProtoJsonUtil.toJsonStr(samplePerson); + String expectedJson = JsonFormat.printer().print(samplePerson); + assertEquals(expectedJson, json); + + json = ProtoJsonUtil.toJsonStr(null); + assertNull(json); } @Test void toProtobuf() { + + Person.Builder builder = Person.newBuilder(); + Person person = (Person) ProtoJsonUtil.toProtobuf(sampleJson, builder); + assertEquals(samplePerson, person); + + String invalidJson = "{ \"name\": \"John Doe\", \"id\": \"not-a-number\" }"; + builder = Person.newBuilder(); + person = (Person) ProtoJsonUtil.toProtobuf(invalidJson, builder); + + assertNull(person); } + } diff --git a/common/src/test/java/org/apache/hertzbeat/common/util/entity/PersonTest.java b/common/src/test/java/org/apache/hertzbeat/common/util/entity/PersonTest.java new file mode 100644 index 00000000000..93e6955bf5d --- /dev/null +++ b/common/src/test/java/org/apache/hertzbeat/common/util/entity/PersonTest.java @@ -0,0 +1,837 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: person.proto + +package org.apache.hertzbeat.common.util.entity; + +@SuppressWarnings("all") +public final class PersonTest { + private PersonTest() {} + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistryLite registry) { + } + + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistry registry) { + registerAllExtensions( + (com.google.protobuf.ExtensionRegistryLite) registry); + } + public interface PersonOrBuilder extends + // @@protoc_insertion_point(interface_extends:org.apache.hertzbeat.common.util.entity.Person) + com.google.protobuf.MessageOrBuilder { + + /** + * string name = 1; + * @return The name. + */ + java.lang.String getName(); + /** + * string name = 1; + * @return The bytes for name. + */ + com.google.protobuf.ByteString + getNameBytes(); + + /** + * int32 id = 2; + * @return The id. + */ + int getId(); + + /** + * string email = 3; + * @return The email. + */ + java.lang.String getEmail(); + /** + * string email = 3; + * @return The bytes for email. + */ + com.google.protobuf.ByteString + getEmailBytes(); + } + /** + * Protobuf type {@code org.apache.hertzbeat.common.util.entity.Person} + */ + public static final class Person extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:org.apache.hertzbeat.common.util.entity.Person) + PersonOrBuilder { + private static final long serialVersionUID = 0L; + // Use Person.newBuilder() to construct. + private Person(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + private Person() { + name_ = ""; + email_ = ""; + } + + @java.lang.Override + @SuppressWarnings({"unused"}) + protected java.lang.Object newInstance( + UnusedPrivateParameter unused) { + return new Person(); + } + + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.apache.hertzbeat.common.util.entity.PersonTest.internal_static_org_apache_hertzbeat_common_util_entity_Person_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.apache.hertzbeat.common.util.entity.PersonTest.internal_static_org_apache_hertzbeat_common_util_entity_Person_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.apache.hertzbeat.common.util.entity.PersonTest.Person.class, org.apache.hertzbeat.common.util.entity.PersonTest.Person.Builder.class); + } + + public static final int NAME_FIELD_NUMBER = 1; + private volatile java.lang.Object name_; + /** + * string name = 1; + * @return The name. + */ + @java.lang.Override + public java.lang.String getName() { + java.lang.Object ref = name_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + name_ = s; + return s; + } + } + /** + * string name = 1; + * @return The bytes for name. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int ID_FIELD_NUMBER = 2; + private int id_; + /** + * int32 id = 2; + * @return The id. + */ + @java.lang.Override + public int getId() { + return id_; + } + + public static final int EMAIL_FIELD_NUMBER = 3; + private volatile java.lang.Object email_; + /** + * string email = 3; + * @return The email. + */ + @java.lang.Override + public java.lang.String getEmail() { + java.lang.Object ref = email_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + email_ = s; + return s; + } + } + /** + * string email = 3; + * @return The bytes for email. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getEmailBytes() { + java.lang.Object ref = email_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + email_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(name_)) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 1, name_); + } + if (id_ != 0) { + output.writeInt32(2, id_); + } + if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(email_)) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 3, email_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(name_)) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, name_); + } + if (id_ != 0) { + size += com.google.protobuf.CodedOutputStream + .computeInt32Size(2, id_); + } + if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(email_)) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(3, email_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.apache.hertzbeat.common.util.entity.PersonTest.Person)) { + return super.equals(obj); + } + org.apache.hertzbeat.common.util.entity.PersonTest.Person other = (org.apache.hertzbeat.common.util.entity.PersonTest.Person) obj; + + if (!getName() + .equals(other.getName())) return false; + if (getId() + != other.getId()) return false; + if (!getEmail() + .equals(other.getEmail())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + NAME_FIELD_NUMBER; + hash = (53 * hash) + getName().hashCode(); + hash = (37 * hash) + ID_FIELD_NUMBER; + hash = (53 * hash) + getId(); + hash = (37 * hash) + EMAIL_FIELD_NUMBER; + hash = (53 * hash) + getEmail().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.apache.hertzbeat.common.util.entity.PersonTest.Person parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.apache.hertzbeat.common.util.entity.PersonTest.Person parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.apache.hertzbeat.common.util.entity.PersonTest.Person parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.apache.hertzbeat.common.util.entity.PersonTest.Person parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.apache.hertzbeat.common.util.entity.PersonTest.Person parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.apache.hertzbeat.common.util.entity.PersonTest.Person parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.apache.hertzbeat.common.util.entity.PersonTest.Person parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static org.apache.hertzbeat.common.util.entity.PersonTest.Person parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + public static org.apache.hertzbeat.common.util.entity.PersonTest.Person parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + public static org.apache.hertzbeat.common.util.entity.PersonTest.Person parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.apache.hertzbeat.common.util.entity.PersonTest.Person parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static org.apache.hertzbeat.common.util.entity.PersonTest.Person parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.apache.hertzbeat.common.util.entity.PersonTest.Person prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code org.apache.hertzbeat.common.util.entity.Person} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:org.apache.hertzbeat.common.util.entity.Person) + org.apache.hertzbeat.common.util.entity.PersonTest.PersonOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.apache.hertzbeat.common.util.entity.PersonTest.internal_static_org_apache_hertzbeat_common_util_entity_Person_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.apache.hertzbeat.common.util.entity.PersonTest.internal_static_org_apache_hertzbeat_common_util_entity_Person_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.apache.hertzbeat.common.util.entity.PersonTest.Person.class, org.apache.hertzbeat.common.util.entity.PersonTest.Person.Builder.class); + } + + // Construct using org.apache.hertzbeat.common.util.entity.PersonTest.Person.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + name_ = ""; + + id_ = 0; + + email_ = ""; + + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.apache.hertzbeat.common.util.entity.PersonTest.internal_static_org_apache_hertzbeat_common_util_entity_Person_descriptor; + } + + @java.lang.Override + public org.apache.hertzbeat.common.util.entity.PersonTest.Person getDefaultInstanceForType() { + return org.apache.hertzbeat.common.util.entity.PersonTest.Person.getDefaultInstance(); + } + + @java.lang.Override + public org.apache.hertzbeat.common.util.entity.PersonTest.Person build() { + org.apache.hertzbeat.common.util.entity.PersonTest.Person result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.apache.hertzbeat.common.util.entity.PersonTest.Person buildPartial() { + org.apache.hertzbeat.common.util.entity.PersonTest.Person result = new org.apache.hertzbeat.common.util.entity.PersonTest.Person(this); + result.name_ = name_; + result.id_ = id_; + result.email_ = email_; + onBuilt(); + return result; + } + + @java.lang.Override + public Builder clone() { + return super.clone(); + } + @java.lang.Override + public Builder setField( + com.google.protobuf.Descriptors.FieldDescriptor field, + java.lang.Object value) { + return super.setField(field, value); + } + @java.lang.Override + public Builder clearField( + com.google.protobuf.Descriptors.FieldDescriptor field) { + return super.clearField(field); + } + @java.lang.Override + public Builder clearOneof( + com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return super.clearOneof(oneof); + } + @java.lang.Override + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + int index, java.lang.Object value) { + return super.setRepeatedField(field, index, value); + } + @java.lang.Override + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + java.lang.Object value) { + return super.addRepeatedField(field, value); + } + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.apache.hertzbeat.common.util.entity.PersonTest.Person) { + return mergeFrom((org.apache.hertzbeat.common.util.entity.PersonTest.Person)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.apache.hertzbeat.common.util.entity.PersonTest.Person other) { + if (other == org.apache.hertzbeat.common.util.entity.PersonTest.Person.getDefaultInstance()) return this; + if (!other.getName().isEmpty()) { + name_ = other.name_; + onChanged(); + } + if (other.getId() != 0) { + setId(other.getId()); + } + if (!other.getEmail().isEmpty()) { + email_ = other.email_; + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + name_ = input.readStringRequireUtf8(); + + break; + } // case 10 + case 16: { + id_ = input.readInt32(); + + break; + } // case 16 + case 26: { + email_ = input.readStringRequireUtf8(); + + break; + } // case 26 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + + private java.lang.Object name_ = ""; + /** + * string name = 1; + * @return The name. + */ + public java.lang.String getName() { + java.lang.Object ref = name_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + name_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string name = 1; + * @return The bytes for name. + */ + public com.google.protobuf.ByteString + getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string name = 1; + * @param value The name to set. + * @return This builder for chaining. + */ + public Builder setName( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + + name_ = value; + onChanged(); + return this; + } + /** + * string name = 1; + * @return This builder for chaining. + */ + public Builder clearName() { + + name_ = getDefaultInstance().getName(); + onChanged(); + return this; + } + /** + * string name = 1; + * @param value The bytes for name to set. + * @return This builder for chaining. + */ + public Builder setNameBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + name_ = value; + onChanged(); + return this; + } + + private int id_ ; + /** + * int32 id = 2; + * @return The id. + */ + @java.lang.Override + public int getId() { + return id_; + } + /** + * int32 id = 2; + * @param value The id to set. + * @return This builder for chaining. + */ + public Builder setId(int value) { + + id_ = value; + onChanged(); + return this; + } + /** + * int32 id = 2; + * @return This builder for chaining. + */ + public Builder clearId() { + + id_ = 0; + onChanged(); + return this; + } + + private java.lang.Object email_ = ""; + /** + * string email = 3; + * @return The email. + */ + public java.lang.String getEmail() { + java.lang.Object ref = email_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + email_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string email = 3; + * @return The bytes for email. + */ + public com.google.protobuf.ByteString + getEmailBytes() { + java.lang.Object ref = email_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + email_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string email = 3; + * @param value The email to set. + * @return This builder for chaining. + */ + public Builder setEmail( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + + email_ = value; + onChanged(); + return this; + } + /** + * string email = 3; + * @return This builder for chaining. + */ + public Builder clearEmail() { + + email_ = getDefaultInstance().getEmail(); + onChanged(); + return this; + } + /** + * string email = 3; + * @param value The bytes for email to set. + * @return This builder for chaining. + */ + public Builder setEmailBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + email_ = value; + onChanged(); + return this; + } + @java.lang.Override + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.setUnknownFields(unknownFields); + } + + @java.lang.Override + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.mergeUnknownFields(unknownFields); + } + + + // @@protoc_insertion_point(builder_scope:org.apache.hertzbeat.common.util.entity.Person) + } + + // @@protoc_insertion_point(class_scope:org.apache.hertzbeat.common.util.entity.Person) + private static final org.apache.hertzbeat.common.util.entity.PersonTest.Person DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.apache.hertzbeat.common.util.entity.PersonTest.Person(); + } + + public static org.apache.hertzbeat.common.util.entity.PersonTest.Person getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public Person parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.apache.hertzbeat.common.util.entity.PersonTest.Person getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + + } + + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_org_apache_hertzbeat_common_util_entity_Person_descriptor; + private static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_org_apache_hertzbeat_common_util_entity_Person_fieldAccessorTable; + + public static com.google.protobuf.Descriptors.FileDescriptor + getDescriptor() { + return descriptor; + } + private static com.google.protobuf.Descriptors.FileDescriptor + descriptor; + static { + java.lang.String[] descriptorData = { + "\n\014person.proto\022\'org.apache.hertzbeat.com" + + "mon.util.entity\"1\n\006Person\022\014\n\004name\030\001 \001(\t\022" + + "\n\n\002id\030\002 \001(\005\022\r\n\005email\030\003 \001(\tB\014B\nPersonTest" + + "b\006proto3" + }; + descriptor = com.google.protobuf.Descriptors.FileDescriptor + .internalBuildGeneratedFileFrom(descriptorData, + new com.google.protobuf.Descriptors.FileDescriptor[] { + }); + internal_static_org_apache_hertzbeat_common_util_entity_Person_descriptor = + getDescriptor().getMessageTypes().get(0); + internal_static_org_apache_hertzbeat_common_util_entity_Person_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_org_apache_hertzbeat_common_util_entity_Person_descriptor, + new java.lang.String[] { "Name", "Id", "Email", }); + } + + // @@protoc_insertion_point(outer_class_scope) +} diff --git a/common/src/test/proto/person.proto b/common/src/test/proto/person.proto new file mode 100644 index 00000000000..6335e76a503 --- /dev/null +++ b/common/src/test/proto/person.proto @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +syntax = "proto3"; + +package org.apache.hertzbeat.common.util.entity; + +option java_outer_classname = "PersonTest"; + +message Person { + string name = 1; + int32 id = 2; + string email = 3; +} From d884278feddf345edc5a27c02d134bc81c4b9076 Mon Sep 17 00:00:00 2001 From: "jiawei.guo" <77717999+asd108908382@users.noreply.github.com> Date: Sun, 7 Jul 2024 09:45:57 +0800 Subject: [PATCH 3/7] [fix] add springboot3.0 autoconfig (#2230) Co-authored-by: jiawei.guo <18613599970@163.con> Co-authored-by: tomsun28 --- ....boot.autoconfigure.AutoConfiguration.imports | 16 ++++++++++++++++ ....boot.autoconfigure.AutoConfiguration.imports | 16 ++++++++++++++++ ....boot.autoconfigure.AutoConfiguration.imports | 16 ++++++++++++++++ ....boot.autoconfigure.AutoConfiguration.imports | 16 ++++++++++++++++ ....boot.autoconfigure.AutoConfiguration.imports | 16 ++++++++++++++++ 5 files changed, 80 insertions(+) create mode 100644 alerter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 collector/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 push/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 warehouse/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports diff --git a/alerter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/alerter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..0becd31fa85 --- /dev/null +++ b/alerter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,16 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +org.apache.hertzbeat.alert.config.AlerterAutoConfiguration \ No newline at end of file diff --git a/collector/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/collector/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..85622a853b4 --- /dev/null +++ b/collector/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,16 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +org.apache.hertzbeat.collector.config.CollectorAutoConfiguration \ No newline at end of file diff --git a/common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..4130e4cb5f5 --- /dev/null +++ b/common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,16 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +org.apache.hertzbeat.common.config.CommonConfig \ No newline at end of file diff --git a/push/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/push/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..5842938edc7 --- /dev/null +++ b/push/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,16 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +org.apache.hertzbeat.push.config.PushAutoConfiguration \ No newline at end of file diff --git a/warehouse/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/warehouse/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..97c492ff37f --- /dev/null +++ b/warehouse/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,16 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +org.apache.hertzbeat.warehouse.WarehouseAutoConfiguration \ No newline at end of file From 53787cc21588805b3834a4c33239b8b958d2d062 Mon Sep 17 00:00:00 2001 From: Calvin Date: Sun, 7 Jul 2024 14:52:13 +0800 Subject: [PATCH 4/7] [bugfix] auto config timezone for Jackson (#2122) Co-authored-by: tomsun28 --- .../hertzbeat/common/util/TimeZoneUtil.java | 56 +++++++++++++++++++ e2e/data/monitor-ftp.json | 8 +-- e2e/data/monitor-http.json | 15 ----- e2e/data/monitor-ping.json | 4 +- e2e/data/monitor-port.json | 6 +- e2e/data/monitor-sitemap.json | 8 +-- e2e/data/monitor-ssl.json | 4 +- e2e/data/monitor-udp.json | 6 +- e2e/data/monitor-website.json | 8 +-- e2e/testsuite.yaml | 4 +- .../component/listener/TimeZoneListener.java | 47 ++++++++++++++++ .../config/CommonCommandLineRunner.java | 23 +++----- .../manager/config/JacksonConfig.java | 45 +++++++++++++++ .../impl/SystemGeneralConfigServiceImpl.java | 26 +++------ 14 files changed, 188 insertions(+), 72 deletions(-) create mode 100644 common/src/main/java/org/apache/hertzbeat/common/util/TimeZoneUtil.java create mode 100644 manager/src/main/java/org/apache/hertzbeat/manager/component/listener/TimeZoneListener.java create mode 100644 manager/src/main/java/org/apache/hertzbeat/manager/config/JacksonConfig.java diff --git a/common/src/main/java/org/apache/hertzbeat/common/util/TimeZoneUtil.java b/common/src/main/java/org/apache/hertzbeat/common/util/TimeZoneUtil.java new file mode 100644 index 00000000000..6a9e157cdd5 --- /dev/null +++ b/common/src/main/java/org/apache/hertzbeat/common/util/TimeZoneUtil.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hertzbeat.common.util; + +import java.util.Locale; +import java.util.TimeZone; +import org.apache.commons.lang3.StringUtils; +import org.apache.hertzbeat.common.constants.CommonConstants; + +/** + * timezone util + */ +public class TimeZoneUtil { + private static final Integer LANG_REGION_LENGTH = 2; + + public static void setTimeZoneAndLocale(String timeZoneId, String locale) { + setTimeZone(timeZoneId); + setLocale(locale); + } + + public static void setTimeZone(String timeZoneId) { + if (StringUtils.isBlank(timeZoneId)) { + return; + } + + TimeZone.setDefault(TimeZone.getTimeZone(timeZoneId)); + } + + public static void setLocale(String locale) { + if (StringUtils.isBlank(locale)) { + return; + } + + String[] arr = locale.split(CommonConstants.LOCALE_SEPARATOR); + if (arr.length == LANG_REGION_LENGTH) { + String language = arr[0]; + String country = arr[1]; + Locale.setDefault(new Locale(language, country)); + } + } +} diff --git a/e2e/data/monitor-ftp.json b/e2e/data/monitor-ftp.json index 3be432eeabc..7ebfc5ee723 100644 --- a/e2e/data/monitor-ftp.json +++ b/e2e/data/monitor-ftp.json @@ -12,22 +12,22 @@ { "field": "host", "type": 1, - "value": "127.0.0.1" + "paramValue": "127.0.0.1" }, { "field": "port", "type": 0, - "value": 21 + "paramValue": 21 }, { "field": "direction", "type": 1, - "value": "127.0.0.1" + "paramValue": "127.0.0.1" }, { "field": "timeout", "type": 0, - "value": 1000 + "paramValue": 1000 }, { "field": "username", diff --git a/e2e/data/monitor-http.json b/e2e/data/monitor-http.json index 841610abc1a..c53fcb7ef27 100644 --- a/e2e/data/monitor-http.json +++ b/e2e/data/monitor-http.json @@ -10,81 +10,66 @@ }, "params": [ { - "display": true, "field": "host", "type": 1, "paramValue": "127.0.0.1" }, { - "display": true, "field": "port", "type": 0, "paramValue": 80 }, { - "display": true, "field": "httpMethod", "type": 1, "paramValue": "GET" }, { - "display": true, "field": "uri", "type": 1 }, { - "display": true, "field": "ssl", "type": 1, "paramValue": false }, { - "display": true, "field": "headers", "type": 3 }, { - "display": true, "field": "params", "type": 3 }, { - "display": true, "field": "timeout", "type": 0 }, { - "display": true, "field": "contentType", "type": 1 }, { - "display": false, "field": "payload", "type": 1 }, { - "display": true, "field": "authType", "type": 1 }, { - "display": true, "field": "username", "type": 1 }, { - "display": true, "field": "password", "type": 1 }, { - "display": true, "field": "keyword", "type": 1 }, { - "display": true, "field": "successCode", "type": 4, "paramValue": "200, 201" diff --git a/e2e/data/monitor-ping.json b/e2e/data/monitor-ping.json index b592b9b5fc8..4bc332a22ef 100644 --- a/e2e/data/monitor-ping.json +++ b/e2e/data/monitor-ping.json @@ -12,12 +12,12 @@ { "field": "host", "type": 1, - "value": "127.0.0.1" + "paramValue": "127.0.0.1" }, { "field": "timeout", "type": 0, - "value": 6000 + "paramValue": 6000 } ] } diff --git a/e2e/data/monitor-port.json b/e2e/data/monitor-port.json index a41a26d2deb..4c2afc621a5 100644 --- a/e2e/data/monitor-port.json +++ b/e2e/data/monitor-port.json @@ -12,17 +12,17 @@ { "field": "host", "type": 1, - "value": "127.0.0.1" + "paramValue": "127.0.0.1" }, { "field": "port", "type": 0, - "value": 80 + "paramValue": 80 }, { "field": "timeout", "type": 0, - "value": 6000 + "paramValue": 6000 } ] } diff --git a/e2e/data/monitor-sitemap.json b/e2e/data/monitor-sitemap.json index 9b630fa832a..2be2d1bf61c 100644 --- a/e2e/data/monitor-sitemap.json +++ b/e2e/data/monitor-sitemap.json @@ -12,22 +12,22 @@ { "field": "host", "type": 1, - "value": "127.0.0.1" + "paramValue": "127.0.0.1" }, { "field": "port", "type": 0, - "value": 80 + "paramValue": 80 }, { "field": "sitemap", "type": 1, - "value": "sitemap.xml" + "paramValue": "sitemap.xml" }, { "field": "ssl", "type": 1, - "value": false + "paramValue": false } ] } diff --git a/e2e/data/monitor-ssl.json b/e2e/data/monitor-ssl.json index 6e36c181d83..6ebbc7a15c6 100644 --- a/e2e/data/monitor-ssl.json +++ b/e2e/data/monitor-ssl.json @@ -12,12 +12,12 @@ { "field": "host", "type": 1, - "value": "127.0.0.1" + "paramValue": "127.0.0.1" }, { "field": "port", "type": 0, - "value": 443 + "paramValue": 443 }, { "field": "uri", diff --git a/e2e/data/monitor-udp.json b/e2e/data/monitor-udp.json index cb076c18ccc..26c41c706e8 100644 --- a/e2e/data/monitor-udp.json +++ b/e2e/data/monitor-udp.json @@ -12,17 +12,17 @@ { "field": "host", "type": 1, - "value": "127.0.0.1" + "paramValue": "127.0.0.1" }, { "field": "port", "type": 0, - "value": 81 + "paramValue": 81 }, { "field": "timeout", "type": 0, - "value": 6000 + "paramValue": 6000 }, { "field": "content", diff --git a/e2e/data/monitor-website.json b/e2e/data/monitor-website.json index db4b520e6d2..804d837ff41 100644 --- a/e2e/data/monitor-website.json +++ b/e2e/data/monitor-website.json @@ -12,21 +12,21 @@ { "field": "host", "type": 1, - "value": "127.0.0.1" + "paramValue": "127.0.0.1" }, { "field": "port", "type": 0, - "value": 80 + "paramValue": 80 }, { "field": "uri", - "type": 1 + "paramValue": 1 }, { "field": "ssl", "type": 1, - "value": false + "paramValue": false }, { "field": "timeout", diff --git a/e2e/testsuite.yaml b/e2e/testsuite.yaml index 4435fc5f126..c78962f802e 100644 --- a/e2e/testsuite.yaml +++ b/e2e/testsuite.yaml @@ -222,7 +222,7 @@ items: ] - name: listTags request: - api: /api/tag + api: /api/tag?pageIndex=0&pageSize=8&type=1 header: Authorization: Bearer {{.login.data.token}} - name: updateTag @@ -236,7 +236,7 @@ items: { "id": {{(index .listTags.data.content 0).id | int64}}, "name": "{{randAlpha 3}}", - "value": "{{randAlpha 3}}", + "tagValue": "{{randAlpha 3}}", "color": "#ff4081", "type": 1, "creator": "admin", diff --git a/manager/src/main/java/org/apache/hertzbeat/manager/component/listener/TimeZoneListener.java b/manager/src/main/java/org/apache/hertzbeat/manager/component/listener/TimeZoneListener.java new file mode 100644 index 00000000000..2801ab7c851 --- /dev/null +++ b/manager/src/main/java/org/apache/hertzbeat/manager/component/listener/TimeZoneListener.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hertzbeat.manager.component.listener; + +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.annotation.Resource; +import java.text.SimpleDateFormat; +import java.util.TimeZone; +import lombok.extern.slf4j.Slf4j; +import org.apache.hertzbeat.common.support.event.SystemConfigChangeEvent; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Component; + +/** + * Listener for config Jackson timezone + */ +@Slf4j +@Component +public class TimeZoneListener { + @Resource + private ObjectMapper objectMapper; + + @EventListener(SystemConfigChangeEvent.class) + public void onEvent(SystemConfigChangeEvent event) { + log.info("{} receive system config change event: {}.", this.getClass().getName(), event.getSource()); + + final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX"); + simpleDateFormat.setTimeZone(TimeZone.getDefault()); + objectMapper.setTimeZone(TimeZone.getDefault()) + .setDateFormat(simpleDateFormat); + } +} diff --git a/manager/src/main/java/org/apache/hertzbeat/manager/config/CommonCommandLineRunner.java b/manager/src/main/java/org/apache/hertzbeat/manager/config/CommonCommandLineRunner.java index 3717188787d..71fc96023d9 100644 --- a/manager/src/main/java/org/apache/hertzbeat/manager/config/CommonCommandLineRunner.java +++ b/manager/src/main/java/org/apache/hertzbeat/manager/config/CommonCommandLineRunner.java @@ -20,11 +20,13 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.usthe.sureness.util.JsonWebTokenUtil; import jakarta.annotation.Resource; +import java.text.SimpleDateFormat; import java.util.Locale; import java.util.Random; import java.util.TimeZone; import org.apache.hertzbeat.common.constants.CommonConstants; import org.apache.hertzbeat.common.entity.manager.GeneralConfig; +import org.apache.hertzbeat.common.util.TimeZoneUtil; import org.apache.hertzbeat.manager.dao.GeneralConfigDao; import org.apache.hertzbeat.manager.pojo.dto.SystemConfig; import org.apache.hertzbeat.manager.pojo.dto.SystemSecret; @@ -46,9 +48,7 @@ @Component @Order(value = Ordered.HIGHEST_PRECEDENCE + 2) public class CommonCommandLineRunner implements CommandLineRunner { - - private static final Integer LANG_REGION_LENGTH = 2; - + private static final String DEFAULT_JWT_SECRET = "CyaFv0bwq2Eik0jdrKUtsA6bx3sDJeFV643R " + "LnfKefTjsIfJLBa2YkhEqEGtcHDTNe4CU6+9 " + "8tVt4bisXQ13rbN0oxhUZR73M6EByXIO+SV5 " @@ -80,17 +80,12 @@ public void run(String... args) throws Exception { // for system config SystemConfig systemConfig = systemGeneralConfigService.getConfig(); if (systemConfig != null) { - if (systemConfig.getTimeZoneId() != null) { - TimeZone.setDefault(TimeZone.getTimeZone(systemConfig.getTimeZoneId())); - } - if (systemConfig.getLocale() != null) { - String[] arr = systemConfig.getLocale().split(CommonConstants.LOCALE_SEPARATOR); - if (arr.length == LANG_REGION_LENGTH) { - String language = arr[0]; - String country = arr[1]; - Locale.setDefault(new Locale(language, country)); - } - } + TimeZoneUtil.setTimeZoneAndLocale(systemConfig.getTimeZoneId(), systemConfig.getLocale()); + + final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX"); + simpleDateFormat.setTimeZone(TimeZone.getDefault()); + objectMapper.setTimeZone(TimeZone.getDefault()) + .setDateFormat(simpleDateFormat); } else { // init system config data systemConfig = SystemConfig.builder().timeZoneId(TimeZone.getDefault().getID()) diff --git a/manager/src/main/java/org/apache/hertzbeat/manager/config/JacksonConfig.java b/manager/src/main/java/org/apache/hertzbeat/manager/config/JacksonConfig.java new file mode 100644 index 00000000000..820f4e35c06 --- /dev/null +++ b/manager/src/main/java/org/apache/hertzbeat/manager/config/JacksonConfig.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hertzbeat.manager.config; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import java.text.SimpleDateFormat; +import java.util.TimeZone; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * jackson config + */ +@Slf4j +@Configuration +public class JacksonConfig { + @Bean + public ObjectMapper objectMapper() { + JavaTimeModule javaTimeModule = new JavaTimeModule(); + final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX"); + simpleDateFormat.setTimeZone(TimeZone.getDefault()); + + return new ObjectMapper() + .registerModule(javaTimeModule) + .setTimeZone(TimeZone.getDefault()) + .setDateFormat(simpleDateFormat); + } +} diff --git a/manager/src/main/java/org/apache/hertzbeat/manager/service/impl/SystemGeneralConfigServiceImpl.java b/manager/src/main/java/org/apache/hertzbeat/manager/service/impl/SystemGeneralConfigServiceImpl.java index fc650a237af..9a87eec4a13 100644 --- a/manager/src/main/java/org/apache/hertzbeat/manager/service/impl/SystemGeneralConfigServiceImpl.java +++ b/manager/src/main/java/org/apache/hertzbeat/manager/service/impl/SystemGeneralConfigServiceImpl.java @@ -21,10 +21,9 @@ import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.annotation.Resource; import java.lang.reflect.Type; -import java.util.Locale; -import java.util.TimeZone; -import org.apache.hertzbeat.common.constants.CommonConstants; +import java.util.Objects; import org.apache.hertzbeat.common.support.event.SystemConfigChangeEvent; +import org.apache.hertzbeat.common.util.TimeZoneUtil; import org.apache.hertzbeat.manager.dao.GeneralConfigDao; import org.apache.hertzbeat.manager.pojo.dto.SystemConfig; import org.springframework.context.ApplicationContext; @@ -35,9 +34,6 @@ */ @Service public class SystemGeneralConfigServiceImpl extends AbstractGeneralConfigServiceImpl { - - private static final Integer LANG_REGION_LENGTH = 2; - @Resource private ApplicationContext applicationContext; @@ -54,20 +50,12 @@ protected SystemGeneralConfigServiceImpl(GeneralConfigDao generalConfigDao, Obje @Override public void handler(SystemConfig systemConfig) { - if (systemConfig != null) { - if (systemConfig.getTimeZoneId() != null) { - TimeZone.setDefault(TimeZone.getTimeZone(systemConfig.getTimeZoneId())); - } - if (systemConfig.getLocale() != null) { - String[] arr = systemConfig.getLocale().split(CommonConstants.LOCALE_SEPARATOR); - if (arr.length == LANG_REGION_LENGTH) { - String language = arr[0]; - String country = arr[1]; - Locale.setDefault(new Locale(language, country)); - } - } - applicationContext.publishEvent(new SystemConfigChangeEvent(applicationContext)); + if (Objects.isNull(systemConfig)) { + return; } + + TimeZoneUtil.setTimeZoneAndLocale(systemConfig.getTimeZoneId(), systemConfig.getLocale()); + applicationContext.publishEvent(new SystemConfigChangeEvent(applicationContext)); } @Override From 044c6d4bad63ab41e2fc1c5a631b4bd40704e19f Mon Sep 17 00:00:00 2001 From: Calvin Date: Sun, 7 Jul 2024 20:33:13 +0800 Subject: [PATCH 5/7] [e2e] complete e2e test case (#2231) --- e2e/testsuite.yaml | 162 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 150 insertions(+), 12 deletions(-) diff --git a/e2e/testsuite.yaml b/e2e/testsuite.yaml index c78962f802e..4ee9bacf04e 100644 --- a/e2e/testsuite.yaml +++ b/e2e/testsuite.yaml @@ -71,22 +71,35 @@ items: expect: bodyFieldsExpect: code: 0 -- name: createHTTPMonitor + +- name: createSitemapMonitor request: api: /api/monitor method: POST header: Authorization: Bearer {{.login.data.token}} Content-type: application/json - bodyFromFile: data/monitor-http.json -- name: createSitemapMonitor + bodyFromFile: data/monitor-sitemap.json +- name: listSitemapMonitor request: - api: /api/monitor - method: POST + api: /api/monitors?pageIndex=0&pageSize=8&app=fullsite header: Authorization: Bearer {{.login.data.token}} - Content-type: application/json - bodyFromFile: data/monitor-sitemap.json +- name: cancelSitemapMonitor + request: + api: /api/monitors/manage?ids={{(index .listSitemapMonitor.data.content 0).id | int64}} + query: + type: JSON + method: DELETE + header: + Authorization: Bearer {{.login.data.token}} +- name: deleteSitemapMonitor + request: + api: /api/monitors?ids={{(index .listSitemapMonitor.data.content 0).id | int64}} + method: DELETE + header: + Authorization: Bearer {{.login.data.token}} + - name: createPortMonitor request: api: /api/monitor @@ -95,6 +108,26 @@ items: Authorization: Bearer {{.login.data.token}} Content-type: application/json bodyFromFile: data/monitor-port.json +- name: listPortMonitor + request: + api: /api/monitors?pageIndex=0&pageSize=8&app=port + header: + Authorization: Bearer {{.login.data.token}} +- name: cancelPortMonitor + request: + api: /api/monitors/manage?ids={{(index .listPortMonitor.data.content 0).id | int64}} + query: + type: JSON + method: DELETE + header: + Authorization: Bearer {{.login.data.token}} +- name: deletePortMonitor + request: + api: /api/monitors?ids={{(index .listPortMonitor.data.content 0).id | int64}} + method: DELETE + header: + Authorization: Bearer {{.login.data.token}} + - name: createSSLMonitor request: api: /api/monitor @@ -103,6 +136,26 @@ items: Authorization: Bearer {{.login.data.token}} Content-type: application/json bodyFromFile: data/monitor-ssl.json +- name: listSSLMonitor + request: + api: /api/monitors?pageIndex=0&pageSize=8&app=ssl_cert + header: + Authorization: Bearer {{.login.data.token}} +- name: cancelSSLMonitor + request: + api: /api/monitors/manage?ids={{(index .listSSLMonitor.data.content 0).id | int64}} + query: + type: JSON + method: DELETE + header: + Authorization: Bearer {{.login.data.token}} +- name: deleteSSLMonitor + request: + api: /api/monitors?ids={{(index .listSSLMonitor.data.content 0).id | int64}} + method: DELETE + header: + Authorization: Bearer {{.login.data.token}} + - name: createPingMonitor request: api: /api/monitor @@ -111,6 +164,26 @@ items: Authorization: Bearer {{.login.data.token}} Content-type: application/json bodyFromFile: data/monitor-ping.json +- name: listPingMonitor + request: + api: /api/monitors?pageIndex=0&pageSize=8&app=ping + header: + Authorization: Bearer {{.login.data.token}} +- name: cancelPingMonitor + request: + api: /api/monitors/manage?ids={{(index .listPingMonitor.data.content 0).id | int64}} + query: + type: JSON + method: DELETE + header: + Authorization: Bearer {{.login.data.token}} +- name: deletePingMonitor + request: + api: /api/monitors?ids={{(index .listPingMonitor.data.content 0).id | int64}} + method: DELETE + header: + Authorization: Bearer {{.login.data.token}} + - name: createUDPMonitor request: api: /api/monitor @@ -119,6 +192,26 @@ items: Authorization: Bearer {{.login.data.token}} Content-type: application/json bodyFromFile: data/monitor-udp.json +- name: listUDPMonitor + request: + api: /api/monitors?pageIndex=0&pageSize=8&app=udp_port + header: + Authorization: Bearer {{.login.data.token}} +- name: cancelUDPMonitor + request: + api: /api/monitors/manage?ids={{(index .listUDPMonitor.data.content 0).id | int64}} + query: + type: JSON + method: DELETE + header: + Authorization: Bearer {{.login.data.token}} +- name: deleteUDPMonitor + request: + api: /api/monitors?ids={{(index .listUDPMonitor.data.content 0).id | int64}} + method: DELETE + header: + Authorization: Bearer {{.login.data.token}} + - name: createWebsiteMonitor request: api: /api/monitor @@ -127,6 +220,26 @@ items: Authorization: Bearer {{.login.data.token}} Content-type: application/json bodyFromFile: data/monitor-website.json +- name: listWebsiteMonitor + request: + api: /api/monitors?pageIndex=0&pageSize=8&app=website + header: + Authorization: Bearer {{.login.data.token}} +- name: cancelWebsiteMonitor + request: + api: /api/monitors/manage?ids={{(index .listWebsiteMonitor.data.content 0).id | int64}} + query: + type: JSON + method: DELETE + header: + Authorization: Bearer {{.login.data.token}} +- name: deleteWebsiteMonitor + request: + api: /api/monitors?ids={{(index .listWebsiteMonitor.data.content 0).id | int64}} + method: DELETE + header: + Authorization: Bearer {{.login.data.token}} + - name: createFTPMonitor request: api: /api/monitor @@ -135,13 +248,37 @@ items: Authorization: Bearer {{.login.data.token}} Content-type: application/json bodyFromFile: data/monitor-ftp.json -- name: listHTTPMonitor +- name: listFTPMonitor request: - api: /api/monitors + api: /api/monitors?pageIndex=0&pageSize=8&app=ftp + header: + Authorization: Bearer {{.login.data.token}} +- name: cancelFTPMonitor + request: + api: /api/monitors/manage?ids={{(index .listFTPMonitor.data.content 0).id | int64}} query: - pageIndex: 0 - pageSize: 8 - app: api + type: JSON + method: DELETE + header: + Authorization: Bearer {{.login.data.token}} +- name: deleteFTPMonitor + request: + api: /api/monitors?ids={{(index .listFTPMonitor.data.content 0).id | int64}} + method: DELETE + header: + Authorization: Bearer {{.login.data.token}} + +- name: createHTTPMonitor + request: + api: /api/monitor + method: POST + header: + Authorization: Bearer {{.login.data.token}} + Content-type: application/json + bodyFromFile: data/monitor-http.json +- name: listHTTPMonitor + request: + api: /api/monitors?pageIndex=0&pageSize=8&app=api header: Authorization: Bearer {{.login.data.token}} - name: cancelHTTPMonitor @@ -158,6 +295,7 @@ items: method: DELETE header: Authorization: Bearer {{.login.data.token}} + - name: listAlertDefines request: api: /api/alert/defines From a618ff00eac5d7a7a19d77f7073751ab6303a83d Mon Sep 17 00:00:00 2001 From: crossoverJie Date: Sun, 7 Jul 2024 20:44:40 +0800 Subject: [PATCH 6/7] [doc] Introduce Committer (#2232) Co-authored-by: tomsun28 --- home/blog/2024-07-07-new-committer.md | 46 ++++++++++++++++++ .../2024-06-07-new-committer.md | 48 +++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 home/blog/2024-07-07-new-committer.md create mode 100644 home/i18n/zh-cn/docusaurus-plugin-content-blog/2024-06-07-new-committer.md diff --git a/home/blog/2024-07-07-new-committer.md b/home/blog/2024-07-07-new-committer.md new file mode 100644 index 00000000000..46d0e8e81e6 --- /dev/null +++ b/home/blog/2024-07-07-new-committer.md @@ -0,0 +1,46 @@ +--- +title: Welcome to HertzBeat Community Committer! +author: crossoverJie +author_title: crossoverJie +author_url: https://github.com/crossoverjie +author_image_url: https://avatars.githubusercontent.com/u/15684156?s=400&v=4 +tags: [opensource, practice] +keywords: [open source monitoring system, alerting system] +--- + + +![hertzBeat](/img/blog/new-committer.png) + +> 🎉 I am very pleased to become a Committer for the Apache HertzBeat project, and I have been invited by the community to introduce myself 🥰. + +I have been working in backend development since I started my career in 2015, engaging in business development, infrastructure, and technical management. Currently, I am working as an infrastructure engineer at an internet company. + +I have always been passionate about the open-source community, and I am also a Committer for Apache Pulsar and a Contributor for OpenTelemetry and VictoriaMetrics. + +# My Connection with HertzBeat + +In April of this year, when HertzBeat entered the Apache Incubator, I happened to see a recommendation on a WeChat public account in my social circle. + +My first reaction was that the name was really well chosen 😄. Then, after looking closely at the features it provides and the problems it solves, I realized its powerful functionalities 💪. + +Since I also need to maintain an observability system at my company, and I have participated in an open-source project called cprobe (which has some similar goals to HertzBeat), I have some experience with monitoring systems and a strong interest in them. Therefore, I read the documentation and quickly started it locally (the community has done a great job in this regard, as many open-source projects lose potential developers right at the initial startup step). + +# Starting Contributions + +My first PR was to fix an incorrect path in a PR template, and the community responded very quickly, which gave me a very positive impression. + +So I started reading some of the core collection code of HertzBeat and found that many logics did not have unit tests at the time. Thus, I began to fill in these tests. + +> Starting with unit tests is indeed a good way to get familiar with a new project. + +While supplementing the unit tests, I also discovered some code logic optimizations and code formatting inconsistencies, which I addressed and reported to the community. + +Similarly, the community's response was swift 🏎, which greatly encouraged my enthusiasm. + +During this process, I also incorporated some excellent experiences from other communities (Pulsar, OpenTelemetry) into HertzBeat. Everyone learned from each other, which is undoubtedly the charm of open source. + +Lastly, I want to thank the community's logicz for inviting me to become a Committer and tom for reviewing my PRs. I wish HertzBeat a successful graduation from the incubator and becoming a star project 🎊. + + + + diff --git a/home/i18n/zh-cn/docusaurus-plugin-content-blog/2024-06-07-new-committer.md b/home/i18n/zh-cn/docusaurus-plugin-content-blog/2024-06-07-new-committer.md new file mode 100644 index 00000000000..3cd89bc0ac2 --- /dev/null +++ b/home/i18n/zh-cn/docusaurus-plugin-content-blog/2024-06-07-new-committer.md @@ -0,0 +1,48 @@ +--- +title: 热烈欢迎 HertzBeat 小伙伴新晋社区 Committer! +author: crossoverJie +author_title: crossoverJie +author_url: https://github.com/crossoverjie +author_image_url: https://avatars.githubusercontent.com/u/15684156?s=400&v=4 +tags: [opensource, practice] +keywords: [open source monitoring system, alerting system] +--- + + +![hertzBeat](/img/blog/new-committer.png) + +> 🎉非常高兴成为 Apache HertzBeat 项目的 Committer,受社区邀请来做一个自我介绍🥰。 + +15 年参与工作至今一直在从事后端研发工作,做过业务开发、基础架构和技术管理;现在在一家互联网公司从事基础架构工程师; + +个人一直热衷于开源社区,同时也是 Apache Pulsar 的 Committer,OpenTelemetry 和 VictoriaMetrics 的 Contributor。 + +# 与 HertzBeat 结缘 + +今年 4 月份,也就是 HertzBeat 进入 Apache 孵化器的时候,我无意间在朋友圈里看到了一篇公众号的推荐。 + +当时第一反应是这个名字取得非常不错😄,然后仔细看了下它所提供的功能,解决了哪些问题,此时就发现功能非常强大💪。 + +因为我在公司内部也需要维护可观测系统,个人参与过一个叫做 cprobe 的开源项目(这个项目的部分目标和 HertzBeat 类似)。 + +所以对监控系统有一些经验同时也非常感兴趣,于是便阅读了文档很快就在本地启动起来了(这一点社区做的很好,许多开源项目第一步启动就要劝退不少潜在的开发者)。 + +# 开始贡献 + +我的第一个 PR 是修改了一个 PR 模版里的错误路径,社区处理的非常快,所以第一次贡献就好感倍增。 + +于是我便尝试开始阅读 HertzBeat 的一些核心采集代码,发现当时许多逻辑都没有提供单测,所以我就开始补全这些测试。 + +> 从单测入手确实是上手一个全新项目的好办法。 + +在补单测的过程中也发现了有些代码逻辑可以优化、代码格式不统一等问题;于是把这些问题都一一解决反馈给了社区。 + +同样的社区响应非常迅速🏎,也极大的鼓舞了我的积极性。 + +在这个过程中我也把在其他社区(Pulsar、OpenTelemetry)的优秀经验借鉴到 HertzBeat,大家取长补短,想必这也是开源的魅力所在吧。 + +最后要感谢社区的 logicz 邀请我成为 Committer,tom 对我 PR 的 review,预祝 HertzBeat 从孵化器毕业成为明星项目🎊。 + + + + From 78621f2f141bff56d5437e67504bd64f2ed2628d Mon Sep 17 00:00:00 2001 From: YuLuo Date: Sun, 7 Jul 2024 20:50:09 +0800 Subject: [PATCH 7/7] [Improve] add TimePeriodUtil & ResourceBundleUtil unit test (#2233) Signed-off-by: yuluo-yx Co-authored-by: tomsun28 --- .../hertzbeat/common/util/TimePeriodUtil.java | 8 ++ .../common/util/ResourceBundleUtilTest.java | 58 +++++++++- .../common/util/TimePeriodUtilTest.java | 107 ++++++++++++++++++ 3 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 common/src/test/java/org/apache/hertzbeat/common/util/TimePeriodUtilTest.java diff --git a/common/src/main/java/org/apache/hertzbeat/common/util/TimePeriodUtil.java b/common/src/main/java/org/apache/hertzbeat/common/util/TimePeriodUtil.java index 5e4cf7704dc..c48d73e1dd8 100644 --- a/common/src/main/java/org/apache/hertzbeat/common/util/TimePeriodUtil.java +++ b/common/src/main/java/org/apache/hertzbeat/common/util/TimePeriodUtil.java @@ -20,10 +20,12 @@ import java.time.Duration; import java.time.Period; import java.time.temporal.TemporalAmount; +import lombok.extern.slf4j.Slf4j; /** * time util */ +@Slf4j public final class TimePeriodUtil { private TimePeriodUtil() { @@ -35,6 +37,12 @@ private TimePeriodUtil() { * @return TemporalAmount */ public static TemporalAmount parseTokenTime(String tokenTime) { + + if (tokenTime == null || tokenTime.length() < 2) { + log.error("tokenTime is invalid"); + return null; + } + if (Character.isUpperCase(tokenTime.charAt(tokenTime.length() - 1))) { return Period.parse("P" + tokenTime); } else { diff --git a/common/src/test/java/org/apache/hertzbeat/common/util/ResourceBundleUtilTest.java b/common/src/test/java/org/apache/hertzbeat/common/util/ResourceBundleUtilTest.java index f453a87cb33..a9b8fb4b544 100644 --- a/common/src/test/java/org/apache/hertzbeat/common/util/ResourceBundleUtilTest.java +++ b/common/src/test/java/org/apache/hertzbeat/common/util/ResourceBundleUtilTest.java @@ -17,19 +17,75 @@ package org.apache.hertzbeat.common.util; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.Mockito.mockStatic; /** * Test case for {@link ResourceBundleUtil} */ +@ExtendWith(MockitoExtension.class) class ResourceBundleUtilTest { + private static final String BUNDLE_NAME = "TestBundle"; + @BeforeEach void setUp() { + Locale.setDefault(Locale.US); } @Test - void getBundle() { + void testGetBundleWithValidBundleName() { + try (MockedStatic mockedResourceBundle = mockStatic(ResourceBundle.class)) { + ResourceBundle mockBundle = Mockito.mock(ResourceBundle.class); + + mockedResourceBundle.when( + () -> ResourceBundle.getBundle( + Mockito.eq(BUNDLE_NAME), + Mockito.any(ResourceBundle.Control.class) + ) + ).thenReturn(mockBundle); + + ResourceBundle bundle = ResourceBundleUtil.getBundle(BUNDLE_NAME); + + assertNotNull(bundle); + assertEquals(mockBundle, bundle); + } } + + @Test + void testGetBundleByInvalidBundleName() { + try (MockedStatic mockedResourceBundle = mockStatic(ResourceBundle.class)) { + mockedResourceBundle.when( + () -> ResourceBundle.getBundle( + Mockito.eq(BUNDLE_NAME), + Mockito.any(ResourceBundle.Control.class) + ) + ).thenThrow(new MissingResourceException("Missing bundle", "ResourceBundle", BUNDLE_NAME)); + + ResourceBundle mockDefaultBundle = Mockito.mock(ResourceBundle.class); + + mockedResourceBundle.when(() -> ResourceBundle.getBundle( + Mockito.eq(BUNDLE_NAME), + Mockito.eq(Locale.US), + Mockito.any(ResourceBundle.Control.class)) + ).thenReturn(mockDefaultBundle); + + ResourceBundle bundle = ResourceBundleUtil.getBundle(BUNDLE_NAME); + + assertNotNull(bundle); + assertEquals(mockDefaultBundle, bundle); + } + } + } diff --git a/common/src/test/java/org/apache/hertzbeat/common/util/TimePeriodUtilTest.java b/common/src/test/java/org/apache/hertzbeat/common/util/TimePeriodUtilTest.java new file mode 100644 index 00000000000..59a7492b86c --- /dev/null +++ b/common/src/test/java/org/apache/hertzbeat/common/util/TimePeriodUtilTest.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hertzbeat.common.util; + +import java.time.Duration; +import java.time.Period; +import java.time.format.DateTimeParseException; +import java.time.temporal.TemporalAmount; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Test case for {@link SnowFlakeIdGenerator} + */ + +class TimePeriodUtilTest { + + @Test + void testParseTokenTime() { + + // Years + TemporalAmount result = TimePeriodUtil.parseTokenTime("1Y"); + assertTrue(result instanceof Period); + assertEquals(Period.ofYears(1), result); + + // Month + result = TimePeriodUtil.parseTokenTime("5M"); + assertTrue(result instanceof Period); + assertEquals(Period.ofMonths(5), result); + + // Day + result = TimePeriodUtil.parseTokenTime("3D"); + assertTrue(result instanceof Period); + assertEquals(Period.ofDays(3), result); + + // Week + result = TimePeriodUtil.parseTokenTime("3W"); + assertTrue(result instanceof Period); + assertEquals(Period.ofWeeks(3), result); + } + + @Test + void testParseTokenTimeDuration() { + + // Minute + TemporalAmount result = TimePeriodUtil.parseTokenTime("30m"); + assertTrue(result instanceof Duration); + assertEquals(Duration.ofMinutes(30), result); + + // Hour + result = TimePeriodUtil.parseTokenTime("2h"); + assertTrue(result instanceof Duration); + assertEquals(Duration.ofHours(2), result); + } + + @Test + void testParseTokenTimeLowerCaseMinute() { + // Lowercase Minute + TemporalAmount result = TimePeriodUtil.parseTokenTime("1m"); + assertTrue(result instanceof Duration); + assertEquals(Duration.ofMinutes(1), result); + } + + @Test + void testParseTokenTimeInvalidInput() { + + // null input + TemporalAmount result = TimePeriodUtil.parseTokenTime(null); + assertNull(result); + + // empty string + result = TimePeriodUtil.parseTokenTime(""); + assertNull(result); + + // string with length < 2 + result = TimePeriodUtil.parseTokenTime("1"); + assertNull(result); + + // invalid format (non-numeric) + Exception exception = assertThrows(DateTimeParseException.class, () -> { + TimePeriodUtil.parseTokenTime("abc"); + }); + assertNotNull(exception.getMessage()); + } + +}