content: /*
   *  Copyright 2016-2024 Qameta Software Inc
   *
   *  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 io.qameta.allure.grpc;
  
  import io.grpc.ManagedChannel;
  import io.grpc.ManagedChannelBuilder;
  import io.grpc.Status;
  import io.grpc.StatusRuntimeException;
  import io.qameta.allure.model.Attachment;
  import io.qameta.allure.model.StepResult;
  import io.qameta.allure.test.AllureResults;
  import org.grpcmock.GrpcMock;
  import org.grpcmock.junit5.GrpcMockExtension;
  import org.junit.jupiter.api.AfterEach;
  import org.junit.jupiter.api.BeforeEach;
  import org.junit.jupiter.api.Test;
  import org.junit.jupiter.api.extension.ExtendWith;
  
  import java.util.Iterator;
  import java.util.Optional;
  
  import static io.qameta.allure.test.RunUtils.runWithinTestContext;
  import static java.util.Arrays.asList;
  import static org.assertj.core.api.Assertions.assertThat;
  import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
  import static org.grpcmock.GrpcMock.serverStreamingMethod;
  import static org.grpcmock.GrpcMock.unaryMethod;
  
  /**
   * @author dtuchs (Dmitry Tuchs).
   */
  @ExtendWith(GrpcMockExtension.class)
  class AllureGrpcTest {
  
      private static final String RESPONSE_MESSAGE = "Hello world!";
  
      private ManagedChannel channel;
      private TestServiceGrpc.TestServiceBlockingStub blockingStub;
  
      @BeforeEach
      void configureMock() {
          channel = ManagedChannelBuilder.forAddress("localhost", GrpcMock.getGlobalPort())
                  .usePlaintext()
                  .build();
          blockingStub = TestServiceGrpc.newBlockingStub(channel)
                  .withInterceptors(new AllureGrpc());
  
          GrpcMock.stubFor(unaryMethod(TestServiceGrpc.getCalculateMethod())
                  .willReturn(Response.newBuilder().setMessage(RESPONSE_MESSAGE).build()));
          GrpcMock.stubFor(serverStreamingMethod(TestServiceGrpc.getCalculateServerStreamMethod())
                  .willReturn(asList(
                          Response.newBuilder().setMessage(RESPONSE_MESSAGE).build(),
                          Response.newBuilder().setMessage(RESPONSE_MESSAGE).build()
                  )));
      }
  
      @AfterEach
      void shutdownChannel() {
          Optional.ofNullable(channel).ifPresent(ManagedChannel::shutdownNow);
      }
  
      @Test
      void shouldCreateRequestAttachment() {
          final Request request = Request.newBuilder()
                  .setTopic("1")
                  .build();
  
          final AllureResults results = execute(request);
  
          assertThat(results.getTestResults().get(0).getSteps())
                  .flatExtracting(StepResult::getAttachments)
                  .extracting(Attachment::getName)
                  .contains("gRPC request");
      }
  
      @Test
      void shouldCreateResponseAttachment() {
          final Request request = Request.newBuilder()
                  .setTopic("1")
                  .build();
  
          final AllureResults results = execute(request);
  
          assertThat(results.getTestResults().get(0).getSteps())
                  .flatExtracting(StepResult::getAttachments)
                  .extracting(Attachment::getName)
                  .contains("gRPC response");
      }
  
      @Test
      void shouldCreateResponseAttachmentForServerStreamingResponse() {
          final Request request = Request.newBuilder()
                  .setTopic("1")
                  .build();
  
          final AllureResults results = executeStreaming(request);
  
          assertThat(results.getTestResults().get(0).getSteps())
                  .flatExtracting(StepResult::getAttachments)
                  .extracting(Attachment::getName)
                  .contains("gRPC response (collection of elements from Server stream)");
      }
  
      @Test
      void shouldCreateResponseAttachmentOnStatusException() {
          final Status status = Status.NOT_FOUND;
          GrpcMock.stubFor(unaryMethod(TestServiceGrpc.getCalculateMethod())
                  .willReturn(status));
  
          final Request request = Request.newBuilder()
                  .setTopic("2")
                  .build();
  
          final AllureResults results = executeException(request);
  
          assertThat(results.getTestResults().get(0).getSteps())
                  .flatExtracting(StepResult::getAttachments)
                  .extracting(Attachment::getName)
                  .contains(status.getCode().name());
      }
  
      protected final AllureResults execute(final Request request) {
          return runWithinTestContext(() -> {
              try {
                  final Response response = blockingStub.calculate(request);
                  assertThat(response.getMessage()).isEqualTo(RESPONSE_MESSAGE);
              } catch (Exception e) {
                  throw new RuntimeException("Could not execute request " + request, e);
              }
          });
      }
      protected final AllureResults executeStreaming(final Request request) {
          return runWithinTestContext(() -> {
              try {
                  Iterator<Response> responseIterator = blockingStub.calculateServerStream(request);
                  while (responseIterator.hasNext()) {
                      assertThat(responseIterator.next().getMessage()).isEqualTo(RESPONSE_MESSAGE);
                  }
              } catch (Exception e) {
                  throw new RuntimeException("Could not execute request " + request, e);
              }
          });
      }
  
      protected final AllureResults executeException(final Request request) {
          return runWithinTestContext(() -> {
                  assertThatExceptionOfType(StatusRuntimeException.class).isThrownBy(() -> blockingStub.calculate(request));
          });
      }
  }
  