-
Notifications
You must be signed in to change notification settings - Fork 90
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: Add powertools specific user-agent-suffix to the AWS SDK v2 cl…
…ients (#1306)
- Loading branch information
Showing
13 changed files
with
304 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
111 changes: 111 additions & 0 deletions
111
.../src/main/java/software/amazon/lambda/powertools/core/internal/UserAgentConfigurator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
/* | ||
* Copyright 2023 Amazon.com, Inc. or its affiliates. | ||
* Licensed 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 software.amazon.lambda.powertools.core.internal; | ||
|
||
import static software.amazon.lambda.powertools.core.internal.SystemWrapper.getenv; | ||
|
||
import java.io.FileInputStream; | ||
import java.io.IOException; | ||
import java.net.URL; | ||
import java.util.Properties; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
|
||
/** | ||
* Can be used to create a string that can server as a User-Agent suffix in requests made with the AWS SDK clients | ||
*/ | ||
public class UserAgentConfigurator { | ||
|
||
public static final String NA = "NA"; | ||
public static final String VERSION_KEY = "powertools.version"; | ||
public static final String PT_FEATURE_VARIABLE = "${PT_FEATURE}"; | ||
public static final String PT_EXEC_ENV_VARIABLE = "${PT_EXEC_ENV}"; | ||
public static final String VERSION_PROPERTIES_FILENAME = "version.properties"; | ||
public static final String AWS_EXECUTION_ENV = "AWS_EXECUTION_ENV"; | ||
private static final Logger LOG = LoggerFactory.getLogger(UserAgentConfigurator.class); | ||
private static final String NO_OP = "no-op"; | ||
private static String ptVersion = getProjectVersion(); | ||
private static String userAgentPattern = "PT/" + PT_FEATURE_VARIABLE + "/" + ptVersion + " PTEnv/" | ||
+ PT_EXEC_ENV_VARIABLE; | ||
|
||
private UserAgentConfigurator() { | ||
throw new IllegalStateException("Utility class. Not meant to be instantiated"); | ||
} | ||
|
||
/** | ||
* Retrieves the project version from the version.properties file | ||
* | ||
* @return the project version | ||
*/ | ||
static String getProjectVersion() { | ||
return getVersionFromProperties(VERSION_PROPERTIES_FILENAME, VERSION_KEY); | ||
} | ||
|
||
|
||
/** | ||
* Retrieves the project version from a properties file. | ||
* The file should be in the resources folder. | ||
* The version is retrieved from the property with the given key. | ||
* | ||
* @param propertyFileName the name of the properties file | ||
* @param versionKey the key of the property that contains the version | ||
* @return the version of the project as configured in the given properties file | ||
*/ | ||
static String getVersionFromProperties(String propertyFileName, String versionKey) { | ||
|
||
URL propertiesFileURI = Thread.currentThread().getContextClassLoader().getResource(propertyFileName); | ||
if (propertiesFileURI != null) { | ||
try (FileInputStream fis = new FileInputStream(propertiesFileURI.getPath())) { | ||
Properties properties = new Properties(); | ||
properties.load(fis); | ||
String version = properties.getProperty(versionKey); | ||
if (version != null && !version.isEmpty()) { | ||
return version; | ||
} | ||
} catch (IOException e) { | ||
LOG.warn("Unable to read {} file. Using default version.", propertyFileName); | ||
LOG.debug("Exception:", e); | ||
} | ||
} | ||
return NA; | ||
} | ||
|
||
/** | ||
* Retrieves the user agent string for the Powertools for AWS Lambda. | ||
* It follows the pattern PT/{PT_FEATURE}/{PT_VERSION} PTEnv/{PT_EXEC_ENV} | ||
* The version of the project is automatically retrieved. | ||
* The PT_EXEC_ENV is automatically retrieved from the AWS_EXECUTION_ENV environment variable. | ||
* If it AWS_EXECUTION_ENV is not set, PT_EXEC_ENV defaults to "NA" | ||
* | ||
* @param ptFeature a custom feature to be added to the user agent string (e.g. idempotency). | ||
* If null or empty, the default PT_FEATURE is used. | ||
* The default PT_FEATURE is "no-op". | ||
* @return the user agent string | ||
*/ | ||
public static String getUserAgent(String ptFeature) { | ||
|
||
String awsExecutionEnv = getenv(AWS_EXECUTION_ENV); | ||
String ptExecEnv = awsExecutionEnv != null ? awsExecutionEnv : NA; | ||
String userAgent = userAgentPattern.replace(PT_EXEC_ENV_VARIABLE, ptExecEnv); | ||
|
||
if (ptFeature == null || ptFeature.isEmpty()) { | ||
ptFeature = NO_OP; | ||
} | ||
return userAgent | ||
.replace(PT_FEATURE_VARIABLE, ptFeature) | ||
.replace(PT_EXEC_ENV_VARIABLE, ptExecEnv); | ||
} | ||
} |
9 changes: 9 additions & 0 deletions
9
powertools-core/src/main/resources-filtered/version.properties
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# The filtered properties can have variables that are filled in by system properties or project properties. | ||
# See https://maven.apache.org/plugins/maven-resources-plugin/examples/filter.html | ||
# | ||
# The values are replaced before copying the resources to the main output directory. Therefore, as soon as the build phase is completed, | ||
# the values should have been replaced if the properties are available and if 'filtering' is set to true in the pom.xml | ||
# | ||
# | ||
# The ${project.version} is retrieved from the respective pom.xml property | ||
powertools.version=${project.version} |
122 changes: 122 additions & 0 deletions
122
.../test/java/software/amazon/lambda/powertools/core/internal/UserAgentConfiguratorTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
/* | ||
* Copyright 2023 Amazon.com, Inc. or its affiliates. | ||
* Licensed 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 software.amazon.lambda.powertools.core.internal; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
import static org.mockito.Mockito.mockStatic; | ||
import static software.amazon.lambda.powertools.core.internal.SystemWrapper.getenv; | ||
import static software.amazon.lambda.powertools.core.internal.UserAgentConfigurator.AWS_EXECUTION_ENV; | ||
import static software.amazon.lambda.powertools.core.internal.UserAgentConfigurator.VERSION_KEY; | ||
import static software.amazon.lambda.powertools.core.internal.UserAgentConfigurator.VERSION_PROPERTIES_FILENAME; | ||
import static software.amazon.lambda.powertools.core.internal.UserAgentConfigurator.getVersionFromProperties; | ||
|
||
import java.io.File; | ||
import java.util.Objects; | ||
import java.util.regex.Pattern; | ||
import org.junit.jupiter.api.Test; | ||
import org.mockito.MockedStatic; | ||
|
||
class UserAgentConfiguratorTest { | ||
|
||
private static final String SEM_VER_PATTERN = "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$"; | ||
private static final String VERSION = UserAgentConfigurator.getProjectVersion(); | ||
|
||
|
||
@Test | ||
void testGetVersion() { | ||
|
||
assertThat(VERSION) | ||
.isNotNull() | ||
.isNotEmpty(); | ||
assertThat(Pattern.matches(SEM_VER_PATTERN, VERSION)).isTrue(); | ||
} | ||
|
||
@Test | ||
void testGetVersionFromProperties_WrongKey() { | ||
String version = getVersionFromProperties(VERSION_PROPERTIES_FILENAME, "some invalid key"); | ||
|
||
assertThat(version) | ||
.isNotNull() | ||
.isEqualTo("NA"); | ||
} | ||
|
||
@Test | ||
void testGetVersionFromProperties_FileNotExist() { | ||
String version = getVersionFromProperties("some file", VERSION_KEY); | ||
|
||
assertThat(version) | ||
.isNotNull() | ||
.isEqualTo("NA"); | ||
} | ||
|
||
@Test | ||
void testGetVersionFromProperties_InvalidFile() { | ||
File f = new File(Objects.requireNonNull(Thread.currentThread().getContextClassLoader() | ||
.getResource("unreadable.properties")).getPath()); | ||
f.setReadable(false); | ||
|
||
String version = getVersionFromProperties("unreadable.properties", VERSION_KEY); | ||
|
||
assertThat(version).isEqualTo("NA"); | ||
} | ||
|
||
@Test | ||
void testGetVersionFromProperties_EmptyVersion() { | ||
String version = getVersionFromProperties("test.properties", VERSION_KEY); | ||
|
||
assertThat(version).isEqualTo("NA"); | ||
} | ||
|
||
@Test | ||
void testGetUserAgent() { | ||
String userAgent = UserAgentConfigurator.getUserAgent("test-feature"); | ||
|
||
assertThat(userAgent) | ||
.isNotNull() | ||
.isEqualTo("PT/test-feature/" + VERSION + " PTEnv/NA"); | ||
|
||
} | ||
|
||
@Test | ||
void testGetUserAgent_NoFeature() { | ||
String userAgent = UserAgentConfigurator.getUserAgent(""); | ||
|
||
assertThat(userAgent) | ||
.isNotNull() | ||
.isEqualTo("PT/no-op/" + VERSION + " PTEnv/NA"); | ||
} | ||
|
||
@Test | ||
void testGetUserAgent_NullFeature() { | ||
String userAgent = UserAgentConfigurator.getUserAgent(null); | ||
|
||
assertThat(userAgent) | ||
.isNotNull() | ||
.isEqualTo("PT/no-op/" + VERSION + " PTEnv/NA"); | ||
} | ||
|
||
@Test | ||
void testGetUserAgent_SetAWSExecutionEnv() { | ||
try (MockedStatic<SystemWrapper> mockedSystemWrapper = mockStatic(SystemWrapper.class)) { | ||
mockedSystemWrapper.when(() -> getenv(AWS_EXECUTION_ENV)).thenReturn("AWS_Lambda_java8"); | ||
String userAgent = UserAgentConfigurator.getUserAgent("test-feature"); | ||
|
||
assertThat(userAgent) | ||
.isNotNull() | ||
.isEqualTo("PT/test-feature/" + VERSION + " PTEnv/AWS_Lambda_java8"); | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
powertools.version= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# This is intentionally left empty | ||
# It used during testing and is set to un-readable to fulfil the test purposes. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.