<!doctype html>

<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <title>RTCPeerConnection No-Media Connection Test</title>
</head>
<body>
  <div id="log"></div>
  <h2>iceConnectionState info</h2>
  <div id="stateinfo">
  </div>

  <!-- These files are in place when executing on W3C. -->
  <script src="/resources/testharness.js"></script>
  <script src="/resources/testharnessreport.js"></script>
  <script src="RTCPeerConnection-helper.js"></script>
  <script type="text/javascript">
  let gFirstConnection = null;
  let gSecondConnection = null;

  function onIceCandidate(otherConnction, event, reject) {
    try {
      otherConnction.addIceCandidate(event.candidate);
    } catch(e) {
      reject(e);
    }
  };

  function onIceConnectionStateChange(done, failed, event) {
    try {
      assert_equals(event.type, 'iceconnectionstatechange');
      assert_not_equals(gFirstConnection.iceConnectionState, "failed",
                        "iceConnectionState of first connection");
      assert_not_equals(gSecondConnection.iceConnectionState, "failed",
                        "iceConnectionState of second connection");
      const stateinfo = document.getElementById('stateinfo');
      stateinfo.innerHTML = 'First: ' + gFirstConnection.iceConnectionState
                          + '<br>Second: ' + gSecondConnection.iceConnectionState;
      // Note: All these combinations are legal states indicating that the
      // call has connected. All browsers should end up in completed/completed,
      // but as of this moment, we've chosen to terminate the test early.
      // TODO: Revise test to ensure completed/completed is reached.
      const allowedStates = [ 'connected', 'completed'];
      if (allowedStates.includes(gFirstConnection.iceConnectionState) &&
          allowedStates.includes(gSecondConnection.iceConnectionState)) {
        done();
      }
    } catch(e) {
      failed(e);
    }
  };

  // This function starts the test.
  promise_test((test) => {
    return new Promise(async (resolve, reject) => {
      gFirstConnection = new RTCPeerConnection(null);
      test.add_cleanup(() => gFirstConnection.close());
      gFirstConnection.onicecandidate =
          (event) => onIceCandidate(gSecondConnection, event, reject);
      gFirstConnection.oniceconnectionstatechange =
          (event) => onIceConnectionStateChange(resolve, reject, event);

      gSecondConnection = new RTCPeerConnection(null);
      test.add_cleanup(() => gSecondConnection.close());
      gSecondConnection.onicecandidate =
          (event) => onIceCandidate(gFirstConnection, event, reject);
      gSecondConnection.oniceconnectionstatechange =
          (event) => onIceConnectionStateChange(resolve, reject, event);

      const offer = await generateVideoReceiveOnlyOffer(gFirstConnection);

      await gFirstConnection.setLocalDescription(offer);

      // This would normally go across the application's signaling solution.
      // In our case, the "signaling" is to call this function.

      await gSecondConnection.setRemoteDescription({ type: 'offer',
                                                     sdp: offer.sdp });

      const answer = await gSecondConnection.createAnswer();

      await gSecondConnection.setLocalDescription(answer);

      assert_equals(gSecondConnection.getSenders().length, 1);
      assert_not_equals(gSecondConnection.getSenders()[0], null);
      assert_not_equals(gSecondConnection.getSenders()[0].transport, null);

      // Similarly, this would go over the application's signaling solution.
      await gFirstConnection.setRemoteDescription({ type: 'answer',
                                                    sdp: answer.sdp });

      // The test is terminated by onIceConnectionStateChange() calling resolve
      // once both connections are connected.
    })
  });
</script>

</body>
</html>
