content: /*
   * Copyright 1999-2018 Alibaba Group Holding Ltd.
   *
   * 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 com.alibaba.nacos.common.http;
  
  import com.alibaba.nacos.api.common.Constants;
  import com.alibaba.nacos.api.exception.runtime.NacosRuntimeException;
  import com.alibaba.nacos.common.constant.HttpHeaderConsts;
  import com.alibaba.nacos.common.http.param.Header;
  import com.alibaba.nacos.common.http.param.Query;
  import com.alibaba.nacos.common.utils.VersionUtils;
  import org.apache.hc.client5.http.ConnectTimeoutException;
  import org.apache.hc.client5.http.classic.methods.HttpDelete;
  import org.apache.hc.client5.http.classic.methods.HttpUriRequestBase;
  import org.apache.hc.core5.http.HttpEntity;
  import org.junit.jupiter.api.Test;
  import org.junit.jupiter.api.extension.ExtendWith;
  import org.mockito.junit.jupiter.MockitoExtension;
  
  import java.io.InputStream;
  import java.io.UnsupportedEncodingException;
  import java.net.SocketTimeoutException;
  import java.net.URI;
  import java.net.URISyntaxException;
  import java.nio.charset.StandardCharsets;
  import java.util.Collections;
  import java.util.LinkedHashMap;
  import java.util.LinkedList;
  import java.util.List;
  import java.util.Map;
  import java.util.concurrent.TimeoutException;
  
  import static org.junit.jupiter.api.Assertions.assertArrayEquals;
  import static org.junit.jupiter.api.Assertions.assertEquals;
  import static org.junit.jupiter.api.Assertions.assertFalse;
  import static org.junit.jupiter.api.Assertions.assertNotEquals;
  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;
  import static org.mockito.Mockito.mock;
  
  @ExtendWith(MockitoExtension.class)
  class HttpUtilsTest {
      
      String exceptUrl = "http://127.0.0.1:8080/v1/api/test";
      
      @Test
      void testBuildHttpUrl1() {
          String targetUrl = HttpUtils.buildUrl(false, "127.0.0.1:8080", "/v1/api/test");
          assertEquals(exceptUrl, targetUrl);
          targetUrl = HttpUtils.buildUrl(false, "127.0.0.1:8080", "v1/api/test");
          assertEquals(exceptUrl, targetUrl);
          targetUrl = HttpUtils.buildUrl(false, "127.0.0.1:8080", "/v1", "/api/test");
          assertEquals(exceptUrl, targetUrl);
          targetUrl = HttpUtils.buildUrl(false, "127.0.0.1:8080", "/v1", "/api", "/test");
          assertEquals(exceptUrl, targetUrl);
          targetUrl = HttpUtils.buildUrl(false, "127.0.0.1:8080", "/v1", "/api/", "/test");
          assertEquals(exceptUrl, targetUrl);
          targetUrl = HttpUtils.buildUrl(false, "127.0.0.1:8080", "/v1", "", "/api/", "/test");
          assertEquals(exceptUrl, targetUrl);
          targetUrl = HttpUtils.buildUrl(false, "127.0.0.1:8080", "/v1", "", null, "/api/", "/test");
          assertEquals(exceptUrl, targetUrl);
          targetUrl = HttpUtils.buildUrl(false, "127.0.0.1:8080", "/v1", "/api/", "test");
          assertEquals(exceptUrl, targetUrl);
          targetUrl = HttpUtils.buildUrl(true, "127.0.0.1:8080", "/v1", "", null, "/api/", "/test");
          assertEquals("https://127.0.0.1:8080/v1/api/test", targetUrl);
      }
      
      @Test
      void testBuildHttpUrl2() {
          assertThrows(IllegalArgumentException.class, () -> {
              String targetUrl = HttpUtils.buildUrl(false, "127.0.0.1:8080", "//v1/api/test");
              assertNotEquals(exceptUrl, targetUrl);
          });
      }
      
      @Test
      void testBuildHttpUrl3() {
          assertThrows(IllegalArgumentException.class, () -> {
              String targetUrl = HttpUtils.buildUrl(false, "127.0.0.1:8080", "/v1", "/api//", "test");
              assertNotEquals(exceptUrl, targetUrl);
          });
      }
      
      @Test
      void testInitRequestHeader() {
          BaseHttpMethod.HttpGetWithEntity httpRequest = new BaseHttpMethod.HttpGetWithEntity("");
          Header header = Header.newInstance();
          header.addParam("k", "v");
          
          HttpUtils.initRequestHeader(httpRequest, header);
          
          org.apache.hc.core5.http.Header[] headers = httpRequest.getHeaders("k");
          assertEquals(1, headers.length);
          assertEquals("k", headers[0].getName());
          assertEquals("v", headers[0].getValue());
      }
      
      @Test
      void testInitRequestEntity1() throws Exception {
          BaseHttpMethod.HttpGetWithEntity httpRequest = new BaseHttpMethod.HttpGetWithEntity("");
          Header header = Header.newInstance();
          header.addParam(HttpHeaderConsts.CONTENT_TYPE, "text/html");
          
          HttpUtils.initRequestEntity(httpRequest, new byte[] {0, 1, 0, 1}, header);
          
          HttpEntity entity = httpRequest.getEntity();
          InputStream contentStream = entity.getContent();
          byte[] bytes = new byte[contentStream.available()];
          contentStream.read(bytes);
          assertArrayEquals(new byte[] {0, 1, 0, 1}, bytes);
          assertEquals("text/html; charset=UTF-8", entity.getContentType());
      }
      
      @Test
      void testInitRequestEntity2() throws Exception {
          BaseHttpMethod.HttpGetWithEntity httpRequest = new BaseHttpMethod.HttpGetWithEntity("");
          Header header = Header.newInstance();
          header.addParam(HttpHeaderConsts.CONTENT_TYPE, "text/html");
          
          HttpUtils.initRequestEntity(httpRequest, Collections.singletonMap("k", "v"), header);
          
          HttpEntity entity = httpRequest.getEntity();
          InputStream contentStream = entity.getContent();
          byte[] bytes = new byte[contentStream.available()];
          contentStream.read(bytes);
          assertEquals("{\"k\":\"v\"}", new String(bytes, Constants.ENCODE));
          assertEquals("text/html; charset=UTF-8", entity.getContentType());
      }
      
      @Test
      void testInitRequestEntity3() throws Exception {
          BaseHttpMethod.HttpGetWithEntity httpRequest = new BaseHttpMethod.HttpGetWithEntity("");
          Header header = Header.newInstance();
          header.addParam(HttpHeaderConsts.CONTENT_TYPE, "text/html");
          
          HttpUtils.initRequestEntity(httpRequest, "common text", header);
          
          HttpEntity entity = httpRequest.getEntity();
          InputStream contentStream = entity.getContent();
          byte[] bytes = new byte[contentStream.available()];
          contentStream.read(bytes);
          assertEquals("common text", new String(bytes, Constants.ENCODE));
          assertEquals("text/html; charset=UTF-8", entity.getContentType());
      }
      
      @Test
      void testInitRequestEntity4() throws Exception {
          BaseHttpMethod.HttpGetWithEntity httpRequest = new BaseHttpMethod.HttpGetWithEntity("");
          
          HttpUtils.initRequestEntity(httpRequest, null, null);
          
          // nothing change
          assertEquals(new BaseHttpMethod.HttpGetWithEntity("").getEntity(), httpRequest.getEntity());
          // assertArrayEquals(new BaseHttpMethod.HttpGetWithEntity("").getAllHeaders(), httpRequest.getAllHeaders());
      }
      
      @Test
      void testInitRequestEntity5() throws Exception {
          HttpDelete httpDelete = new HttpDelete("");
          
          HttpUtils.initRequestEntity(httpDelete, null, null);
          
          // nothing change
          assertEquals(new HttpDelete("").getMethod(), httpDelete.getMethod());
          // assertArrayEquals(new HttpDelete("").getAllHeaders(), httpDelete.getAllHeaders());
      }
      
      @Test
      void testInitRequestFromEntity1() throws Exception {
          BaseHttpMethod.HttpGetWithEntity httpRequest = new BaseHttpMethod.HttpGetWithEntity("");
          
          HttpUtils.initRequestFromEntity(httpRequest, Collections.singletonMap("k", "v"), "UTF-8");
          
          HttpEntity entity = httpRequest.getEntity();
          InputStream contentStream = entity.getContent();
          byte[] bytes = new byte[contentStream.available()];
          contentStream.read(bytes);
          assertEquals("k=v", new String(bytes, StandardCharsets.UTF_8));
      }
      
      @Test
      void testInitRequestFromEntity2() throws Exception {
          BaseHttpMethod.HttpGetWithEntity httpRequest = new BaseHttpMethod.HttpGetWithEntity("");
          
          HttpUtils.initRequestFromEntity(httpRequest, null, "UTF-8");
          
          // nothing change
          assertEquals(new BaseHttpMethod.HttpGetWithEntity("").getEntity(), httpRequest.getEntity());
      }
      
      @Test
      void testInitRequestFromEntity3() throws Exception {
          BaseHttpMethod.HttpGetWithEntity httpRequest = new BaseHttpMethod.HttpGetWithEntity("");
          
          HttpUtils.initRequestFromEntity(httpRequest, Collections.emptyMap(), "UTF-8");
          
          // nothing change
          assertEquals(new BaseHttpMethod.HttpGetWithEntity("").getEntity(), httpRequest.getEntity());
      }
      
      @Test
      void testInitRequestFromEntity4() throws Exception {
          BaseHttpMethod.HttpGetWithEntity httpRequest = new BaseHttpMethod.HttpGetWithEntity("");
          
          HttpUtils.initRequestFromEntity(mock(HttpUriRequestBase.class), Collections.emptyMap(), "UTF-8");
          
          // nothing change
          assertEquals(new BaseHttpMethod.HttpGetWithEntity("").getEntity(), httpRequest.getEntity());
      }
      
      @Test
      void testInitRequestFromEntity5() throws Exception {
          HttpDelete httpDelete = new HttpDelete("");
          
          HttpUtils.initRequestFromEntity(httpDelete, Collections.singletonMap("k", "v"), "UTF-8");
          
          // nothing change
          assertEquals(new HttpDelete("").getMethod(), httpDelete.getMethod());
          assertArrayEquals(new HttpDelete("").getHeaders(), httpDelete.getHeaders());
      }
      
      @Test
      void testTranslateParameterMap() throws Exception {
          Map<String, String[]> map = Collections.singletonMap("K", new String[] {"V1", "V2"});
          Map<String, String> resultMap = HttpUtils.translateParameterMap(map);
          assertEquals(Collections.singletonMap("K", "V1"), resultMap);
      }
      
      @Test
      void testDecode() throws UnsupportedEncodingException {
          // % - %25, { - %7B, } - %7D
          assertEquals("{k,v}", HttpUtils.decode("%7Bk,v%7D", "UTF-8"));
          assertEquals("{k,v}", HttpUtils.decode("%257Bk,v%257D", "UTF-8"));
      }
      
      @Test
      void testEncodingParamsMapWithNullOrEmpty() throws UnsupportedEncodingException {
          assertNull(HttpUtils.encodingParams((Map<String, String>) null, "UTF-8"));
          assertNull(HttpUtils.encodingParams(Collections.emptyMap(), "UTF-8"));
      }
      
      @Test
      void testEncodingParamsMap() throws UnsupportedEncodingException {
          Map<String, String> params = new LinkedHashMap<>();
          params.put("a", "");
          params.put("b", "x");
          params.put("uriChar", "=");
          params.put("chinese", "测试");
          assertEquals("b=x&uriChar=%3D&chinese=%E6%B5%8B%E8%AF%95&", HttpUtils.encodingParams(params, "UTF-8"));
      }
      
      @Test
      void testEncodingParamsListWithNull() throws UnsupportedEncodingException {
          assertNull(HttpUtils.encodingParams((List<String>) null, "UTF-8"));
      }
      
      @Test
      void testEncodingParamsList() throws UnsupportedEncodingException {
          List<String> params = new LinkedList<>();
          params.add("a");
          params.add("");
          params.add("b");
          params.add("x");
          params.add("uriChar");
          params.add("=");
          params.add("chinese");
          params.add("测试");
          assertEquals("a=&b=x&uriChar=%3D&chinese=%E6%B5%8B%E8%AF%95", HttpUtils.encodingParams(params, "UTF-8"));
      }
      
      @Test
      void testBuildUriForEmptyQuery() throws URISyntaxException {
          URI actual = HttpUtils.buildUri("www.aliyun.com", null);
          assertEquals("www.aliyun.com", actual.toString());
          actual = HttpUtils.buildUri("www.aliyun.com", new Query());
          assertEquals("www.aliyun.com", actual.toString());
      }
      
      @Test
      void testBuildUri() throws URISyntaxException {
          Query query = new Query();
          query.addParam("a", "");
          query.addParam("b", "x");
          query.addParam("uriChar", "=");
          query.addParam("chinese", "测试");
          URI actual = HttpUtils.buildUri("www.aliyun.com", query);
          assertEquals("www.aliyun.com?" + query.toQueryUrl(), actual.toString());
      }
      
      @Test
      void testIsTimeoutException() {
          assertFalse(HttpUtils.isTimeoutException(new NacosRuntimeException(0)));
          assertTrue(HttpUtils.isTimeoutException(new TimeoutException()));
          assertTrue(HttpUtils.isTimeoutException(new SocketTimeoutException()));
          assertTrue(HttpUtils.isTimeoutException(new ConnectTimeoutException("")));
          assertTrue(HttpUtils.isTimeoutException(new NacosRuntimeException(0, new TimeoutException())));
      }
      
      @Test
      void testBuilderHeader() {
          Header header = HttpUtils.builderHeader("Test");
          assertNotNull(header);
          assertEquals(header.getValue(HttpHeaderConsts.CLIENT_VERSION_HEADER), VersionUtils.version);
          assertEquals(header.getValue(HttpHeaderConsts.USER_AGENT_HEADER), VersionUtils.getFullClientVersion());
          assertEquals("gzip,deflate,sdch", header.getValue(HttpHeaderConsts.ACCEPT_ENCODING));
          assertEquals("Keep-Alive", header.getValue(HttpHeaderConsts.CONNECTION));
          assertNotNull(header.getValue(HttpHeaderConsts.REQUEST_ID));
          assertEquals("Test", header.getValue(HttpHeaderConsts.REQUEST_MODULE));
      }
  }
  