使用 Netlfix DGS 测试自定义反应式 WebGraphQlInterceptor

问题描述 投票:0回答:1

我有一个正在运行的 WebGraphQLInterceptor,它根据身份验证和 GraphQL 查询参数的组合进行一些授权检查。

我想编写单元测试来单独测试我的

CustomGraphQlInterceptor
,而不是作为我们正在构建的更大 servlet 的一部分。但我无法在测试期间执行代码。

简化代码:

@Component
class CustomGraphQlInterceptor : WebGraphQlInterceptor {
  private val logger = LoggerFactory.getLogger(javaClass)

  // you can ignore IDE errors about being unable to Autowire this bean, it will
  // successfully autowire at runtime.
  @Suppress("SpringJavaInjectionPointsAutowiringInspection")
  @Autowired
  private lateinit var externalAuthorizationService: ExternalAuthorizationService

  override fun intercept(
    request: WebGraphQlRequest,
    chain: WebGraphQlInterceptor.Chain,
  ): Mono<WebGraphQlResponse> {
    logger.info("Validating request: $request")
    logger.info("Context is  ${ReactiveSecurityContextHolder.getContext()}")
    return ReactiveSecurityContextHolder.getContext().flatMap { securityContext ->
      val authentication = securityContext.authentication
      if (authentication is JwtAuthenticationToken) {
       val externalId = authentication.tokenAttributes["externalId"] as? String

      val queryVariable = request.variables["queryVariable"]
      
      val isAuthorized: Boolean = externalAuthorizationService.isAuthorized(externalId, queryVariable)

     if (!isAuthorized) {
       return@flatMap Mono.error(IllegalAccessException("not authorized"))
     }
     return@flatMap chain.next(request)
  }
}

我的测试是这样的:

@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.CLASS)
@ExtendWith(SpringExtension::class)
@SpringBootTest(
    classes = [DgsAutoConfiguration::class, TestConfig::class],
    webEnvironment = WebEnvironment.RANDOM_PORT,
    properties = ["spring.main.web-application-type=reactive", "spring.profiles.active=test"],
)
@TestExecutionListeners(
  ReactorContextTestExecutionListener::class,
  mergeMode = TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS,
)
class SupplierGraphQlInterceptorTest {
  @Autowired
  private lateinit var customGraphQlInterceptor: CustomGraphQlInterceptor

  @MockkBean
  private lateinit var externalAuthorizationService: ExternalAuthorizationService

  @BeforeEach
  fun setupAuthorized() {
    TestSecurityContextHolder.setAuthentication(
      JwtAuthenticationToken(
        Jwt(
          "token",
          Instant.now(),
          Instant.MAX,
          mapOf(
            "alg" to "none",
          ),
          mapOf(
            "externalId" to "1",
          ),
        ),
      ),
    )
  }

  @Test
  fun testUserIsAuthorized() {
    val request =
      WebGraphQlRequest(
        URI("http://localhost:8080/graphql"), // uri
        HttpHeaders(CollectionUtils.toMultiValueMap(mapOf())), // headers
        null, // cookies
        null, // remote address
        mapOf(), // attributes
        mapOf( // body
          "query" to "{someQuery{id name}}",
          "operationName" to "POST",
          "variables" to mapOf("queryVariable" to "ABC"),
        ),
        "1", // id
        null, // local
      )

    every {
      authorizationService.isAuthorized(1, "ABC")
    } returns true

    val chain = mockk<WebGraphQlInterceptor.Chain>()
    every { chain.next(any()) } returns Mono.just(mockk<WebGraphQlResponse>())

    StepVerifier
      .create(
        supplierGraphQlInterceptor.intercept(request, chain),
      ).expectNextMatches { it is WebGraphQlResponse }
      .verifyComplete()
  }
}

失败了

java.lang.AssertionError:期望“expectNextMatches”失败(预期:onNext();实际:onComplete())

我是 DGS、Spring 和 kotlin 的新手,所以我确信我在这里至少做错了几件事。

spring kotlin spring-graphql netflix-dgs
1个回答
0
投票

我能够解决这个问题。使用

ReactorContextTestExecutionListener
是一个错误,这可以做得更干净:

@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.CLASS)
@ExtendWith(SpringExtension::class)
@SpringBootTest(
    classes = [DgsAutoConfiguration::class, TestConfig::class],
    webEnvironment = WebEnvironment.RANDOM_PORT,
    properties = ["spring.main.web-application-type=reactive", "spring.profiles.active=test"],
)
class CustomGraphQlInterceptorTest {
  @Autowired
  private lateinit var customGraphQlInterceptor: CustomGraphQlInterceptor

  @MockkBean
  private lateinit var externalAuthorizationService: ExternalAuthorizationService
@Test
  fun testUserIsAuthorized() {
    val request =
      WebGraphQlRequest(
        URI("http://localhost:8080/graphql"), // uri
        HttpHeaders(CollectionUtils.toMultiValueMap(mapOf())), // headers
        null, // cookies
        null, // remote address
        mapOf(), // attributes
        mapOf( // body
          "query" to "{someQuery{id name}}",
          "operationName" to "POST",
          "variables" to mapOf("queryVariable" to "ABC"),
        ),
        "1", // id
        null, // local
      )

    every {
      authorizationService.isAuthorized(1, "ABC")
    } returns true

    val jwt =
      JwtAuthenticationToken(
        Jwt(
          "token",
          Instant.now(),
          Instant.MAX,
          mapOf(
            "alg" to "none",
          ),
          mapOf(
            "externalId" to 1,
          ),
        ),
      )

    val securityContext: SecurityContext = mockk()
    every { securityContext.authentication } returns jwt

    val chain = mockk<WebGraphQlInterceptor.Chain>()
    every { chain.next(any()) } returns Mono.just(mockk<WebGraphQlResponse>())

    StepVerifier
      .create(
        supplierGraphQlInterceptor.intercept(request, chain).contextWrite(
          ReactiveSecurityContextHolder
            .withSecurityContext(Mono.just(securityContext)),
        ),
      ).expectNextMatches { it is WebGraphQlResponse }
      .verifyComplete()
  }
}
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.