<springdoc.version>2.0.2</springdoc.version>
<springdoc.openapi-ui.version>1.6.14</springdoc.openapi-ui.version>
<exec.skip>true</exec.skip>
+
</properties>
<dependencies>
<dependency>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-inline</artifactId>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>io.projectreactor.kafka</groupId>
<artifactId>reactor-kafka</artifactId>
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
});
}
- private static void restartApplication() {
- if (applicationContext == null) {
- logger.info("Cannot restart in unittest");
- return;
- }
- ApplicationArguments args = applicationContext.getBean(ApplicationArguments.class);
-
- Thread thread = new Thread(() -> {
- applicationContext.close();
- applicationContext = SpringApplication.run(Application.class, args.getSourceArgs());
- });
-
- thread.setDaemon(false);
- thread.start();
- }
-
}
}
private void onError(Throwable t) {
- if (t instanceof WebClientResponseException) {
- WebClientResponseException e = (WebClientResponseException) t;
+ if (t instanceof WebClientResponseException e) {
logger.debug("Response error: {}", e.getResponseBodyAsString());
}
}
}
}
+ @SuppressWarnings("java:S6204")
private SslContext createSslContextRejectingUntrustedPeers(String trustStorePath, String trustStorePass,
KeyManagerFactory keyManager)
throws NoSuchAlgorithmException, CertificateException, IOException, KeyStoreException {
public static ResponseEntity<Object> create(Throwable e, HttpStatus code) {
if (e instanceof RuntimeException) {
code = HttpStatus.INTERNAL_SERVER_ERROR;
- } else if (e instanceof ServiceException) {
- ServiceException se = (ServiceException) e;
- if (se.getHttpStatus() != null) {
- code = se.getHttpStatus();
- }
+ } else if (e instanceof ServiceException se && se.getHttpStatus() != null) {
+ code = se.getHttpStatus();
}
return create(e.toString(), code);
}
return Mono.just("OK");
}
- private Path path(String name) {
+ public Path path(String name) {
return Path.of(applicationConfig.getPmFilesPath(), name);
}
getS3AsynchClient(applicationConfig);
}
+ @SuppressWarnings({"java:S3010", "java:S2209"})
+ public S3ObjectStore(ApplicationConfig applicationConfig, S3AsyncClient s3AsynchClient) {
+ this.applicationConfig = applicationConfig;
+ this.s3AsynchClient = s3AsynchClient;
+ }
+
private static synchronized S3AsyncClient getS3AsynchClient(ApplicationConfig applicationConfig) {
if (applicationConfig.isS3Enabled() && s3AsynchClient == null) {
s3AsynchClient = getS3AsyncClientBuilder(applicationConfig).build();
package org.oran.pmproducer.filter;
import com.google.gson.GsonBuilder;
-
-import java.lang.invoke.MethodHandles;
import java.util.Collection;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
public class FilterFactory {
- private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
private static com.google.gson.Gson gson = new GsonBuilder().disableHtmlEscaping().create();
private FilterFactory() {}
-// ============LICENSE_START===============================================
-// Copyright (C) 2023 Nordix Foundation. All rights reserved.
-// ========================================================================
-// 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.
-// ============LICENSE_END=================================================
-//
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2023 Nordix Foundation
+ * %%
+ * 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.
+ * ========================LICENSE_END===================================
+ */
package org.oran.pmproducer.oauth2;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.JsonMappingException;
-
import java.util.Base64;
import java.util.HashSet;
import java.util.Set;
-
import lombok.ToString;
-
import org.apache.kafka.common.security.oauthbearer.OAuthBearerToken;
import org.oran.pmproducer.exceptions.ServiceException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
public class OAuthBearerTokenJwt implements OAuthBearerToken {
- private static final Logger logger = LoggerFactory.getLogger(OAuthBearerTokenJwt.class);
private static final com.google.gson.Gson gson = new com.google.gson.GsonBuilder().disableHtmlEscaping().create();
private final String jwtTokenRaw;
}
public static OAuthBearerTokenJwt create(String tokenRaw)
- throws ServiceException, JsonMappingException, JsonProcessingException {
+ throws ServiceException {
String[] chunks = tokenRaw.split("\\.");
Base64.Decoder decoder = Base64.getUrlDecoder();
if (chunks.length < 2) {
-// ============LICENSE_START===============================================
-// Copyright (C) 2023 Nordix Foundation. All rights reserved.
-// ========================================================================
-// 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.
-// ============LICENSE_END=================================================
-//
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * Copyright (C) 2023 Nordix Foundation
+ *
+ * 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.
+ * ========================LICENSE_END===================================
+ */
package org.oran.pmproducer.oauth2;
}
@Override
- public void close() {}
+ public void close() {
+ /*This method intentionally left empty.
+ Close functionality will be implemented later.*/
+ }
@Override
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
if (!this.isConfigured)
throw new IllegalStateException("Callback handler not configured");
for (Callback callback : callbacks) {
- logger.debug("callback " + callback.toString());
- if (callback instanceof OAuthBearerTokenCallback) {
- handleCallback((OAuthBearerTokenCallback) callback);
- } else if (callback instanceof SaslExtensionsCallback) {
- handleCallback((SaslExtensionsCallback) callback);
+ logger.debug("callback {}", callback);
+ if (callback instanceof OAuthBearerTokenCallback oAuthBearerTokenCallback) {
+ handleCallback(oAuthBearerTokenCallback);
+ } else if (callback instanceof SaslExtensionsCallback saslExtensionsCallback) {
+ handleCallback(saslExtensionsCallback);
} else {
logger.error("Unsupported callback: {}", callback);
throw new UnsupportedCallbackException(callback);
}
}
+ public boolean isConfigured() {
+ return isConfigured;
+ }
+
}
private static SecurityContext instance;
@Setter
+ @Getter
private Path authTokenFilePath;
public SecurityContext(@Value("${app.auth-token-file}") String authTokenFilename) {
- instance = this;
+ instance = this; //NOSONAR
if (!authTokenFilename.isEmpty()) {
this.authTokenFilePath = Path.of(authTokenFilename);
}
@Schema(name = "producer_info_type_info", description = "Information for an Information Type")
public class ProducerInfoTypeInfo {
+ @SuppressWarnings("java:S1874")
@Schema(name = "info_job_data_schema", description = "Json schema for the job data", required = true)
@SerializedName("info_job_data_schema")
@JsonProperty(value = "info_job_data_schema", required = true)
public Object jobDataSchema;
+ @SuppressWarnings("java:S1874")
@Schema(name = "info_type_information", description = "Type specific information for the information type",
required = true)
@SerializedName("info_type_information")
description = "The body of the Information Producer callbacks for Information Job creation and deletion")
public class ProducerJobInfo {
+ @SuppressWarnings("java:S1874")
@Schema(name = "info_job_identity", description = "Identity of the Information Job", required = true)
@SerializedName("info_job_identity")
@JsonProperty("info_job_identity")
@Schema(name = "producer_registration_info", description = "Information for an Information Producer")
public class ProducerRegistrationInfo {
+ @SuppressWarnings("java:S1874")
@Schema(name = "supported_info_types", description = "Supported Information Type IDs", required = true)
@SerializedName("supported_info_types")
@JsonProperty(value = "supported_info_types", required = true)
public Collection<String> supportedTypeIds;
+ @SuppressWarnings("java:S1874")
@Schema(name = "info_job_callback_url", description = "callback for Information Job", required = true)
@SerializedName("info_job_callback_url")
@JsonProperty(value = "info_job_callback_url", required = true)
public String jobCallbackUrl;
+ @SuppressWarnings("java:S1874")
@Schema(name = "info_producer_supervision_callback_url", description = "callback for producer supervision",
required = true)
@SerializedName("info_producer_supervision_callback_url")
private final List<Observer> observers = new ArrayList<>();
private final ApplicationConfig appConfig;
+ @SuppressWarnings("java:S1172")
public Jobs(@Autowired ApplicationConfig applicationConfig, @Autowired SecurityContext securityContext,
@Autowired ApplicationConfig appConfig) {
this.appConfig = appConfig;
}
public void addJob(String id, InfoType type, String owner, String lastUpdated, Parameters parameters)
- throws ServiceException {
-
+ {
Job job = new Job(id, type, owner, lastUpdated, parameters, this.appConfig);
this.put(job);
}
this.consumerFaultCounter = 0;
}
+ @SuppressWarnings("java:S1172")
public void handleException(Throwable t) {
++this.consumerFaultCounter;
}
}
}
+ @SuppressWarnings("java:S1172")
private Object jsonSchemaObject(InfoType type) throws IOException, ServiceException {
final String schemaFile = "/typeSchemaPmData.json";
return jsonObject(readSchemaFile(schemaFile));
}
}
- private boolean isEqual(ProducerRegistrationInfo a, ProducerRegistrationInfo b) {
- return a.jobCallbackUrl.equals(b.jobCallbackUrl) //
- && a.producerSupervisionCallbackUrl.equals(b.producerSupervisionCallbackUrl) //
- && a.supportedTypeIds.size() == b.supportedTypeIds.size();
- }
-
private ProducerRegistrationInfo producerRegistrationInfo() {
return ProducerRegistrationInfo.builder() //
.jobCallbackUrl(baseUrl() + ProducerCallbacksController.JOB_URL) //
public class TopicListeners {
private static final Logger logger = LoggerFactory.getLogger(TopicListeners.class);
+ @SuppressWarnings("java:S1700")
@Getter
private final Map<String, TopicListener> topicListeners = new HashMap<>(); // Key is typeId
}
String msgString = kafkaReceiver.receivedKafkaOutput.valueAsString();
- assertThat(msgString).contains("pmCounterNumber0");
- assertThat(msgString).doesNotContain("pmCounterNumber1");
+ assertThat(msgString)
+ .contains("pmCounterNumber0")
+ .doesNotContain("pmCounterNumber1");
assertThat(kafkaReceiver.receivedKafkaOutput.getTypeIdFromHeaders()).isEqualTo(PM_TYPE_ID);
assertThat(kafkaReceiver.receivedKafkaOutput.getSourceNameFromHeaders()).isEqualTo("HTTPST2-0"); // This is from
// the file
--- /dev/null
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2023 Nordix Foundation
+ * %%
+ * 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.
+ * ========================LICENSE_END===================================
+ */
+
+package org.oran.pmproducer.datastore;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.when;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.oran.pmproducer.configuration.ApplicationConfig;
+
+@ExtendWith(MockitoExtension.class)
+class DataStoreTest {
+
+ @Mock
+ private ApplicationConfig mockAppConfig;
+
+ @Test
+ void testCreateWithS3Enabled() {
+ when(mockAppConfig.isS3Enabled()).thenReturn(true);
+ when(mockAppConfig.getS3EndpointOverride()).thenReturn("https://dummy-s3-bucket.s3.amazonaws.com");
+ when(mockAppConfig.getS3AccessKeyId()).thenReturn("test-access-key-id");
+ when(mockAppConfig.getS3SecretAccessKey()).thenReturn("test-access-key-secret");
+ DataStore dataStore = DataStore.create(mockAppConfig);
+ assertTrue(dataStore instanceof S3ObjectStore);
+ }
+
+ @Test
+ void testCreateWithS3Disabled() {
+ when(mockAppConfig.isS3Enabled()).thenReturn(false);
+ DataStore dataStore = DataStore.create(mockAppConfig);
+ assertTrue(dataStore instanceof FileStore);
+ }
+}
--- /dev/null
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019-2023 Nordix Foundation.
+ * ================================================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.oran.pmproducer.datastore;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+import java.nio.file.FileVisitor;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.oran.pmproducer.configuration.ApplicationConfig;
+import org.springframework.test.context.ContextConfiguration;
+import reactor.core.publisher.Mono;
+import reactor.test.StepVerifier;
+
+@ContextConfiguration(classes = {FileStore.class})
+@ExtendWith(MockitoExtension.class)
+class FileStoreTest {
+
+ @Mock
+ private ApplicationConfig appConfig;
+
+ private FileStore fileStore;
+
+ @Mock
+ private Path mockPath;
+
+ @BeforeEach
+ void setup() {
+ MockitoAnnotations.initMocks(this);
+ fileStore = new FileStore(appConfig);
+
+ when(appConfig.getPmFilesPath()).thenReturn("/path/to/pm/files");
+ }
+
+ @Test
+ void testListObjects() {
+ when(appConfig.getPmFilesPath()).thenReturn("PM Files Path");
+ fileStore.listObjects(DataStore.Bucket.FILES, "Prefix");
+ verify(appConfig).getPmFilesPath();
+ }
+ @Test
+ void testListObjects3() {
+ when(appConfig.getPmFilesPath()).thenReturn("PM Files Path");
+ fileStore.listObjects(DataStore.Bucket.LOCKS, "Prefix");
+ verify(appConfig).getPmFilesPath();
+ }
+
+ @Test
+ void testListObjects_WithExistingFiles() {
+ List<Path> fileList = new ArrayList<>();
+ fileList.add(Path.of("/path/to/pm/files/file1.txt"));
+ fileList.add(Path.of("/path/to/pm/files/file2.txt"));
+
+ when(appConfig.getPmFilesPath()).thenReturn("/path/to/pm/files");
+
+ // Mock Files.walk() to return the prepared stream
+ try (MockedStatic<Files> filesMockedStatic = mockStatic(Files.class)) {
+ filesMockedStatic.when(() -> Files.walk(any(), anyInt()))
+ .thenReturn(fileList.stream());
+
+ StepVerifier.create(fileStore.listObjects(DataStore.Bucket.FILES, ""))
+ .expectNext("file1.txt")
+ .expectNext("file2.txt")
+ .expectComplete();
+ }
+ }
+ @Test
+ void testReadObject() {
+ when(appConfig.getPmFilesPath()).thenReturn("PM Files Path");
+ fileStore.readObject(DataStore.Bucket.FILES, "foo.txt");
+ verify(appConfig).getPmFilesPath();
+ }
+ @Test
+ void testReadObject2() {
+ when(appConfig.getPmFilesPath()).thenReturn("PM Files Path");
+ fileStore.readObject(DataStore.Bucket.LOCKS, "foo.txt");
+ verify(appConfig).getPmFilesPath();
+ }
+
+ @Test
+ void testReadObject_WithExistingFile() {
+ byte[] content = "Hello, world!".getBytes();
+ Path filePath = Path.of("/path/to/pm/files/test.txt");
+
+ try (MockedStatic<Files> filesMockedStatic = mockStatic(Files.class)) {
+ filesMockedStatic.when(() -> Files.readAllBytes(eq(filePath)))
+ .thenReturn(content);
+
+ StepVerifier.create(fileStore.readObject(DataStore.Bucket.FILES, "test.txt"))
+ .expectNext(content)
+ .verifyComplete();
+ }
+ }
+ @Test
+ void testCreateLock() {
+ when(appConfig.getPmFilesPath()).thenReturn("PM Files Path");
+ fileStore.createLock("Name");
+ verify(appConfig, atLeast(1)).getPmFilesPath();
+ }
+ @Test
+ void testCreateLock3() {
+ when(appConfig.getPmFilesPath()).thenReturn("");
+ fileStore.createLock("/");
+ verify(appConfig, atLeast(1)).getPmFilesPath();
+ }
+ @Test
+ void testDeleteLock() {
+ when(appConfig.getPmFilesPath()).thenReturn("PM Files Path");
+ fileStore.deleteLock("Name");
+ verify(appConfig).getPmFilesPath();
+ }
+ @Test
+ void testDeleteLock2() {
+ when(appConfig.getPmFilesPath()).thenReturn("");
+ fileStore.deleteLock("//");
+ verify(appConfig).getPmFilesPath();
+ }
+ @Test
+ void testDeleteObject() {
+ when(appConfig.getPmFilesPath()).thenReturn("PM Files Path");
+ fileStore.deleteObject(DataStore.Bucket.FILES, "Name");
+ verify(appConfig).getPmFilesPath();
+ }
+ @Test
+ void testDeleteObject2() {
+ when(appConfig.getPmFilesPath()).thenReturn("PM Files Path");
+ fileStore.deleteObject(DataStore.Bucket.LOCKS, "Name");
+ verify(appConfig).getPmFilesPath();
+ }
+
+ @Test
+ void testPath() {
+ when(appConfig.getPmFilesPath()).thenReturn("PM Files Path");
+ fileStore.path("Name");
+ verify(appConfig).getPmFilesPath();
+ }
+
+ @Test
+ void testDeleteBucket() {
+ when(appConfig.getPmFilesPath()).thenReturn("PM Files Path");
+ fileStore.deleteBucket(DataStore.Bucket.FILES);
+ verify(appConfig).getPmFilesPath();
+ }
+ @Test
+ void testDeleteBucket2() throws IOException {
+ try (MockedStatic<Files> mockFiles = mockStatic(Files.class)) {
+ mockFiles.when(() -> Files.walkFileTree(Mockito.<Path>any(), Mockito.<FileVisitor<Path>>any()))
+ .thenReturn(Paths.get(System.getProperty("java.io.tmpdir"), "test.txt"));
+ mockFiles.when(() -> Files.exists(Mockito.<Path>any(), (LinkOption[]) any())).thenReturn(true);
+ when(appConfig.getPmFilesPath()).thenReturn("");
+ fileStore.deleteBucket(DataStore.Bucket.LOCKS);
+ mockFiles.verify(() -> Files.exists(Mockito.<Path>any(), (LinkOption[]) any()));
+ mockFiles.verify(() -> Files.walkFileTree(Mockito.<Path>any(), Mockito.<FileVisitor<Path>>any()));
+ verify(appConfig).getPmFilesPath();
+ }
+ }
+ @Test
+ void testDeleteBucket3() throws IOException {
+ try (MockedStatic<Files> mockFiles = mockStatic(Files.class)) {
+ mockFiles.when(() -> Files.walkFileTree(Mockito.<Path>any(), Mockito.<FileVisitor<Path>>any()))
+ .thenThrow(new IOException("OK"));
+ mockFiles.when(() -> Files.exists(Mockito.<Path>any(), (LinkOption[]) any())).thenReturn(true);
+ when(appConfig.getPmFilesPath()).thenReturn("");
+ fileStore.deleteBucket(DataStore.Bucket.LOCKS);
+ mockFiles.verify(() -> Files.exists(Mockito.<Path>any(), (LinkOption[]) any()));
+ mockFiles.verify(() -> Files.walkFileTree(Mockito.<Path>any(), Mockito.<FileVisitor<Path>>any()));
+ verify(appConfig, atLeast(1)).getPmFilesPath();
+ }
+ }
+
+ @Test
+ void testCreateLock_Success() throws IOException {
+ Path lockPath = Path.of("/path/to/pm/files/locks/lock.txt");
+
+ when(appConfig.getPmFilesPath()).thenReturn("/path/to/pm/files");
+
+ try (MockedStatic<Files> filesMockedStatic = mockStatic(Files.class)) {
+ filesMockedStatic.when(() -> Files.createDirectories(lockPath.getParent()))
+ .thenReturn(lockPath.getParent());
+
+ try (MockedStatic<Path> pathMockedStatic = mockStatic(Path.class)) {
+ filesMockedStatic.when(() -> Files.createFile(any(Path.class))).thenReturn(lockPath);
+
+ String name = "test.txt";
+ String[] pathComponents = {"pmFiles", name};
+
+ when(fileStore.path(Arrays.toString(pathComponents))).thenReturn(mockPath);
+ Path path = fileStore.path(Arrays.toString(pathComponents));
+ assertEquals(mockPath, path);
+ }
+ }
+ }
+
+ @Test
+ void testCopyFileTo_Failure() {
+ // Define dummy values for testing
+ Path from = Paths.get("non-existent-file.txt");
+ String to = "destination-folder";
+
+ // Use StepVerifier to test the method
+ Mono<String> resultMono = fileStore.copyFileTo(from, to);
+
+ StepVerifier.create(resultMono)
+ .expectError(IOException.class)
+ .verify();
+ }
+}
+
--- /dev/null
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2023 Nordix Foundation
+ * %%
+ * 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.
+ * ========================LICENSE_END===================================
+ */
+
+package org.oran.pmproducer.datastore;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.net.URISyntaxException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.oran.pmproducer.configuration.ApplicationConfig;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+import reactor.test.StepVerifier;
+import software.amazon.awssdk.core.ResponseBytes;
+import software.amazon.awssdk.core.async.AsyncRequestBody;
+import software.amazon.awssdk.core.async.AsyncResponseTransformer;
+import software.amazon.awssdk.services.s3.S3AsyncClient;
+import software.amazon.awssdk.services.s3.model.CreateBucketRequest;
+import software.amazon.awssdk.services.s3.model.CreateBucketResponse;
+import software.amazon.awssdk.services.s3.model.DeleteBucketRequest;
+import software.amazon.awssdk.services.s3.model.DeleteBucketResponse;
+import software.amazon.awssdk.services.s3.model.DeleteObjectRequest;
+import software.amazon.awssdk.services.s3.model.DeleteObjectResponse;
+import software.amazon.awssdk.services.s3.model.DeleteObjectsRequest;
+import software.amazon.awssdk.services.s3.model.DeleteObjectsResponse;
+import software.amazon.awssdk.services.s3.model.GetObjectRequest;
+import software.amazon.awssdk.services.s3.model.GetObjectResponse;
+import software.amazon.awssdk.services.s3.model.HeadObjectRequest;
+import software.amazon.awssdk.services.s3.model.HeadObjectResponse;
+import software.amazon.awssdk.services.s3.model.ListObjectsRequest;
+import software.amazon.awssdk.services.s3.model.ListObjectsResponse;
+import software.amazon.awssdk.services.s3.model.PutObjectRequest;
+import software.amazon.awssdk.services.s3.model.PutObjectResponse;
+import software.amazon.awssdk.services.s3.model.S3Object;
+
+
+@ExtendWith(MockitoExtension.class)
+class S3ObjectStoreTest {
+
+ @Mock
+ private ApplicationConfig appConfig;
+
+ @Mock
+ private S3AsyncClient s3AsynchClient;
+
+ private S3ObjectStore s3ObjectStore;
+
+ @BeforeEach
+ void setup() {
+ Mockito.lenient().when(appConfig.getS3EndpointOverride()).thenReturn("https://dummy-s3-bucket.s3.amazonaws.com");
+ Mockito.lenient().when(appConfig.getS3AccessKeyId()).thenReturn("test-access-key-id");
+ Mockito.lenient().when(appConfig.getS3SecretAccessKey()).thenReturn("test-access-key-secret");
+
+ Mockito.lenient().when(appConfig.getS3Bucket()).thenReturn("test-bucket");
+ Mockito.lenient().when(appConfig.getS3LocksBucket()).thenReturn("test-lock-bucket");
+ Mockito.lenient().when(appConfig.isS3Enabled()).thenReturn(true);
+
+ s3ObjectStore = new S3ObjectStore(appConfig, s3AsynchClient);
+ }
+
+ @Test
+ void createS3Bucket() {
+ CreateBucketRequest request = CreateBucketRequest.builder()
+ .bucket("test-bucket")
+ .build();
+
+ when(s3AsynchClient.createBucket(any(CreateBucketRequest.class)))
+ .thenReturn(CompletableFuture.completedFuture(CreateBucketResponse.builder().build()));
+
+ Mono<String> result = s3ObjectStore.create(DataStore.Bucket.FILES);
+
+ verify(s3AsynchClient, atLeast(1)).createBucket(any(CreateBucketRequest.class));
+
+ StepVerifier.create(result).expectNext("test-bucket").verifyComplete();
+
+ assertThat(result.block()).isEqualTo("test-bucket");
+ }
+
+ @Test
+ void listObjects() {
+ String prefix = "prefix/";
+
+ ListObjectsResponse response1 = ListObjectsResponse.builder()
+ .contents(createS3Object("object1"))
+ .isTruncated(true)
+ .nextMarker("marker1")
+ .build();
+
+ ListObjectsResponse response2 = ListObjectsResponse.builder()
+ .contents(createS3Object("object2"))
+ .isTruncated(false)
+ .build();
+
+ when(s3AsynchClient.listObjects(any(ListObjectsRequest.class)))
+ .thenReturn(CompletableFuture.completedFuture(response1),
+ CompletableFuture.completedFuture(response2));
+
+ Flux<String> result = s3ObjectStore.listObjects(DataStore.Bucket.FILES, prefix);
+
+ verify(s3AsynchClient, atLeast(1)).listObjects(any(ListObjectsRequest.class));
+
+ StepVerifier.create(result)
+ .expectNext("object1")
+ .expectNext("object2")
+ .verifyComplete();
+
+ // Collect the results into a list
+ List<String> resultList = result.collectList().block();
+
+ assertEquals(Arrays.asList("object1", "object2"), resultList);
+ }
+
+ @Test
+ void testCreateLockWithExistingHead() {
+ HeadObjectResponse headObjectResponse = HeadObjectResponse.builder().build();
+
+ when(s3AsynchClient.headObject(any(HeadObjectRequest.class)))
+ .thenReturn(CompletableFuture.completedFuture(headObjectResponse));
+
+ Mono<Boolean> result = s3ObjectStore.createLock("lockName");
+
+ StepVerifier.create(result)
+ .expectNext(false)
+ .verifyComplete();
+
+ assertThat(result.block()).isFalse();
+ }
+
+ @Test
+ void testCreateLockWithoutExistingHead() {
+ HeadObjectResponse headObjectResponse = null;
+ Mockito.doReturn(CompletableFuture.completedFuture(headObjectResponse))
+ .when(s3AsynchClient)
+ .headObject(any(HeadObjectRequest.class));
+
+ Mono<Boolean> result = s3ObjectStore.createLock("lockName");
+
+ StepVerifier.create(result)
+ .expectComplete()
+ .verify();
+
+ Boolean resultVal = result.block();
+
+ assertThat(resultVal).isNull();
+ }
+
+
+ @Test
+ void deleteLock() {
+ when(s3AsynchClient.deleteObject(any(DeleteObjectRequest.class)))
+ .thenReturn(CompletableFuture.completedFuture(DeleteObjectResponse.builder().build()));
+
+ Mono<Boolean> result = s3ObjectStore.deleteLock("lock-name");
+
+ StepVerifier.create(result)
+ .expectNext(true)
+ .verifyComplete();
+
+ assertThat(result.block()).isTrue();
+ }
+
+ @Test
+ void testDeleteObject() {
+ when(s3AsynchClient.deleteObject(any(DeleteObjectRequest.class)))
+ .thenReturn(CompletableFuture.completedFuture(DeleteObjectResponse.builder().build()));
+
+ Mono<Boolean> result = s3ObjectStore.deleteObject(DataStore.Bucket.LOCKS, "objectName");
+
+ StepVerifier.create(result)
+ .expectNext(true)
+ .verifyComplete();
+
+ assertThat(result.block()).isTrue();
+ }
+
+ @Test
+ void testDeleteBucket_Success() {
+ DeleteBucketRequest request = DeleteBucketRequest.builder() //
+ .bucket("test-bucket")
+ .build();
+
+ Mockito.lenient().when(s3AsynchClient.deleteBucket(any(DeleteBucketRequest.class)))
+ .thenReturn(CompletableFuture.completedFuture(DeleteBucketResponse.builder().build()));
+
+ DeleteObjectsRequest objectRequest = DeleteObjectsRequest.builder() //
+ .bucket("test-bucket")
+ .build();
+
+ Mockito.lenient().when(s3AsynchClient.deleteObjects(any(DeleteObjectsRequest.class)))
+ .thenReturn(CompletableFuture.completedFuture(DeleteObjectsResponse.builder().build()));
+
+ String prefix = "prefix/";
+
+ ListObjectsResponse response1 = ListObjectsResponse.builder()
+ .contents(createS3Object("object1"))
+ .isTruncated(true)
+ .nextMarker("marker1")
+ .build();
+
+ ListObjectsResponse response2 = ListObjectsResponse.builder()
+ .contents(createS3Object("object2"))
+ .isTruncated(false)
+ .build();
+
+ when(s3AsynchClient.listObjects(any(ListObjectsRequest.class)))
+ .thenReturn(CompletableFuture.completedFuture(response1),
+ CompletableFuture.completedFuture(response2));
+
+ Mono<String> result = s3ObjectStore.deleteBucket(DataStore.Bucket.FILES);
+
+ StepVerifier.create(result)
+ .expectNext("NOK")
+ .verifyComplete();
+ }
+
+ @Test
+ void testCopyFileTo_Success() throws URISyntaxException {
+ PutObjectRequest request = PutObjectRequest.builder() //
+ .bucket("test-bucket") //
+ .key("test-access-key-id") //
+ .build();
+
+ when(s3AsynchClient.putObject(any(PutObjectRequest.class), any(AsyncRequestBody.class)))
+ .thenAnswer(invocation -> {
+ CompletableFuture<PutObjectResponse> future = CompletableFuture.completedFuture(
+ PutObjectResponse.builder().build()
+ );
+ return future;
+ });
+
+ Path testFile = Paths.get(getClass().getResource("/org/oran/pmproducer/datastore/file.txt").toURI());
+
+ Mono<String> result = s3ObjectStore.copyFileTo(testFile, "test-key");
+
+ StepVerifier.create(result)
+ .expectNext("test-key")
+ .verifyComplete();
+ }
+
+ @Test
+ void testReadObject() {
+ // Mock the getObject method to return a CompletableFuture with ResponseBytes
+ when(s3AsynchClient.getObject(any(GetObjectRequest.class), any(AsyncResponseTransformer.class)))
+ .thenAnswer(invocation -> {
+ ResponseBytes<GetObjectResponse> responseBytes = ResponseBytes.fromByteArray(
+ GetObjectResponse.builder().build(),
+ "Hello, World!".getBytes(StandardCharsets.UTF_8)
+ );
+ CompletableFuture<ResponseBytes<GetObjectResponse>> future = CompletableFuture.completedFuture(
+ responseBytes
+ );
+ return future;
+ });
+
+ // Call the method under test
+ Mono<byte[]> result = s3ObjectStore.readObject(DataStore.Bucket.FILES, "test-key");
+
+ byte[] expectedBytes = "Hello, World!".getBytes(StandardCharsets.UTF_8);
+ StepVerifier.create(result)
+ .consumeNextWith(actualBytes -> Assertions.assertArrayEquals(expectedBytes, actualBytes))
+ .verifyComplete();
+ }
+
+ @Test
+ void testPutObject() {
+ // Mock the putObject method to return a CompletableFuture with PutObjectResponse
+ when(s3AsynchClient.putObject(any(PutObjectRequest.class), any(AsyncRequestBody.class)))
+ .thenAnswer(invocation -> {
+ CompletableFuture<PutObjectResponse> future = CompletableFuture.completedFuture(
+ PutObjectResponse.builder().build()
+ );
+ return future;
+ });
+
+ // Call the method under test
+ Mono<String> result = s3ObjectStore.putObject(DataStore.Bucket.FILES, "test-key", "Hello, World!");
+
+ // Verify the Mono's behavior using StepVerifier
+ StepVerifier.create(result)
+ .expectNext("test-key")
+ .verifyComplete();
+ }
+
+ private S3Object createS3Object(String key) {
+ return S3Object.builder().key(key).build();
+ }
+}
--- /dev/null
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2023 Nordix Foundation
+ * %%
+ * 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.
+ * ========================LICENSE_END===================================
+ */
+
+package org.oran.pmproducer.oauth2;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.oran.pmproducer.exceptions.ServiceException;
+import org.springframework.test.context.ContextConfiguration;
+
+@ContextConfiguration(classes = {OAuthBearerTokenJwtTest.class})
+@ExtendWith(MockitoExtension.class)
+class OAuthBearerTokenJwtTest {
+
+ private OAuthBearerTokenJwt token;
+
+ @BeforeEach
+ void setUp() throws ServiceException, JsonProcessingException {
+ String validJwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"; // Replace with a valid JWT token for testing
+ token = OAuthBearerTokenJwt.create(validJwt);
+ }
+
+ @Test
+ void testCreateValidToken() {
+ assertNotNull(token);
+ }
+
+ @Test
+ void testCreateInvalidToken() {
+ assertThrows(ServiceException.class, () -> OAuthBearerTokenJwt.create("invalid_token"));
+ }
+
+ @Test
+ void testTokenValue() {
+ assertEquals("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c", token.value());
+ }
+
+ @Test
+ void testTokenScope() {
+ assertEquals(0, token.scope().size());
+ assertFalse(token.scope().contains(""));
+ }
+
+ @Test
+ void testTokenLifetimeMs() {
+ assertEquals(Long.MAX_VALUE, token.lifetimeMs());
+ }
+
+ @Test
+ void testTokenPrincipalName() {
+ assertEquals("1234567890", token.principalName());
+ }
+
+ @Test
+ void testTokenStartTimeMs() {
+ assertEquals(1516239022L, token.startTimeMs());
+ }
+
+ @Test
+ void testCreateTokenFromInvalidPayload() throws ServiceException {
+ // Create a JWT with an invalid payload (missing fields)
+ String invalidPayload = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9";
+ assertThrows(ServiceException.class, () -> OAuthBearerTokenJwt.create(invalidPayload));
+ }
+
+ @Test
+ void testCreateTokenWithValidPayload() throws ServiceException, JsonProcessingException {
+ // Create a JWT with a valid payload
+ String validPayload = "eyJzdWIiOiAiVGVzdCIsICJleHAiOiAxNjM1MTUwMDAwLCAiaWF0IjogMTYzNTA5NTAwMCwgInNjb3BlIjogInNjb3BlX3Rva2VuIiwgImp0aSI6ICJmb28ifQ==";
+ OAuthBearerTokenJwt jwt = OAuthBearerTokenJwt.create("header." + validPayload + ".signature");
+
+ assertNotNull(jwt);
+ assertEquals("header." + validPayload + ".signature", jwt.value());
+ assertEquals(1, jwt.scope().size());
+ assertEquals("scope_token", jwt.scope().iterator().next());
+ assertEquals("Test", jwt.principalName());
+ assertEquals(1635095000, jwt.startTimeMs());
+ }
+
+ @Test
+ void testCreateThrowsExceptionWithInvalidToken() throws ServiceException {
+ String tokenRaw = "your_mocked_token_here";
+ assertThrows(ServiceException.class, () -> OAuthBearerTokenJwt.create(tokenRaw));
+ }
+}
+
--- /dev/null
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2023 Nordix Foundation
+ * %%
+ * 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.
+ * ========================LICENSE_END===================================
+ */
+
+package org.oran.pmproducer.oauth2;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.login.AppConfigurationEntry;
+import org.apache.kafka.common.security.auth.SaslExtensionsCallback;
+import org.apache.kafka.common.security.oauthbearer.OAuthBearerLoginModule;
+import org.apache.kafka.common.security.oauthbearer.OAuthBearerTokenCallback;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+class OAuthKafkaAuthenticateLoginCallbackHandlerTest {
+
+ private OAuthKafkaAuthenticateLoginCallbackHandler callbackHandler;
+
+ @BeforeEach
+ void setUp() {
+ callbackHandler = new OAuthKafkaAuthenticateLoginCallbackHandler();
+ }
+
+ @Test
+ void testConfigureWithValidSaslMechanismAndConfigEntry() {
+ String saslMechanism = OAuthBearerLoginModule.OAUTHBEARER_MECHANISM;
+ List<AppConfigurationEntry> jaasConfigEntries = Collections.singletonList(Mockito.mock(AppConfigurationEntry.class));
+
+ callbackHandler.configure(new HashMap<>(), saslMechanism, jaasConfigEntries);
+
+ assertTrue(callbackHandler.isConfigured());
+ }
+
+ @SuppressWarnings("java:S5778")
+ @Test
+ void testConfigureWithInvalidSaslMechanism() {
+ String invalidSaslMechanism = "InvalidMechanism";
+ List<AppConfigurationEntry> jaasConfigEntries = Collections.singletonList(Mockito.mock(AppConfigurationEntry.class));
+
+ assertThrows(IllegalArgumentException.class, () -> callbackHandler.configure(new HashMap<>(), invalidSaslMechanism, jaasConfigEntries));
+
+ assertFalse(callbackHandler.isConfigured());
+ }
+
+ @SuppressWarnings("java:S5778")
+ @Test
+ void testConfigureWithEmptyJaasConfigEntries() {
+ String saslMechanism = OAuthBearerLoginModule.OAUTHBEARER_MECHANISM;
+ List<AppConfigurationEntry> emptyJaasConfigEntries = Collections.emptyList();
+
+ assertThrows(IllegalArgumentException.class, () -> callbackHandler.configure(new HashMap<>(), saslMechanism, emptyJaasConfigEntries));
+
+ assertFalse(callbackHandler.isConfigured());
+ }
+
+ @Test
+ void testHandleSaslExtensionsCallback() throws IOException, UnsupportedCallbackException {
+ String saslMechanism = OAuthBearerLoginModule.OAUTHBEARER_MECHANISM;
+ List<AppConfigurationEntry> jaasConfigEntries = Collections.singletonList(Mockito.mock(AppConfigurationEntry.class));
+
+ callbackHandler.configure(new HashMap<>(), saslMechanism, jaasConfigEntries);
+ SaslExtensionsCallback callback = mock(SaslExtensionsCallback.class);
+
+ callbackHandler.handle(new Callback[]{callback});
+ verify(callback).extensions(any());
+ }
+
+ @Test
+ void testHandleUnsupportedCallback() {
+ Callback unsupportedCallback = mock(Callback.class);
+ String saslMechanism = OAuthBearerLoginModule.OAUTHBEARER_MECHANISM;
+ List<AppConfigurationEntry> jaasConfigEntries = Collections.singletonList(Mockito.mock(AppConfigurationEntry.class));
+
+ callbackHandler.configure(new HashMap<>(), saslMechanism, jaasConfigEntries);
+ assertThrows(UnsupportedCallbackException.class, () -> callbackHandler.handle(new Callback[]{unsupportedCallback}));
+ }
+
+ @Test
+ void testHandleOAuthBearerTokenCallback() throws IOException, UnsupportedCallbackException {
+
+ String saslMechanism = OAuthBearerLoginModule.OAUTHBEARER_MECHANISM;
+ List<AppConfigurationEntry> jaasConfigEntries = Collections.singletonList(Mockito.mock(AppConfigurationEntry.class));
+ String validJwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c";
+
+ callbackHandler.configure(new HashMap<>(), saslMechanism, jaasConfigEntries);
+
+ OAuthBearerTokenCallback oauthBearerTokenCallback = Mockito.mock(OAuthBearerTokenCallback.class);
+ SecurityContext securityContextMock = Mockito.mock(SecurityContext.class);
+ when(oauthBearerTokenCallback.token()).thenReturn(null); // Ensure the callback has no token initially
+ when(oauthBearerTokenCallback.token()).thenAnswer(invocation -> {
+ return OAuthBearerTokenJwt.create(validJwt);
+ });
+
+ when(securityContextMock.getBearerAuthToken()).thenReturn(validJwt);
+ callbackHandler.handle(new Callback[]{oauthBearerTokenCallback});
+ verify(oauthBearerTokenCallback).token();
+ }
+}
+
--- /dev/null
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2023 Nordix Foundation
+ * %%
+ * 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.
+ * ========================LICENSE_END===================================
+ */
+
+package org.oran.pmproducer.oauth2;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.nio.file.Path;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.MockitoAnnotations;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+@ExtendWith(MockitoExtension.class)
+class SecurityContextTest {
+
+ @BeforeEach
+ void setUp() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @Test
+ void testConstructorWithAuthTokenFilename() {
+ SecurityContext securityContext = new SecurityContext("auth-token-file.txt");
+ assertNotNull(securityContext.getAuthTokenFilePath());
+ assertEquals(Path.of("auth-token-file.txt"), securityContext.getAuthTokenFilePath());
+ }
+
+ @Test
+ void testConstructorWithoutAuthTokenFilename() {
+ SecurityContext securityContext = new SecurityContext("");
+ assertNull(securityContext.getAuthTokenFilePath());
+ }
+
+ @Test
+ void testIsConfigured() {
+ SecurityContext securityContext = new SecurityContext("auth-token-file.txt");
+ assertTrue(securityContext.isConfigured());
+ }
+
+ @Test
+ void testIsNotConfigured() {
+ SecurityContext securityContext = new SecurityContext("");
+ assertFalse(securityContext.isConfigured());
+ }
+
+ @Test
+ void testGetBearerAuthToken() {
+ assertEquals("", SecurityContext.getInstance().getBearerAuthToken());
+ assertEquals("", (new SecurityContext("foo.txt")).getBearerAuthToken());
+ }
+
+ @Test
+ void testGetBearerAuthTokenWhenNotConfigured() {
+ SecurityContext securityContext = new SecurityContext("");
+ assertEquals("", securityContext.getBearerAuthToken());
+ }
+}
+
--- /dev/null
+Hi, How are you?
\ No newline at end of file