Extends WindowManager to handle the following new cases:
  * one-time WINDOW_UPDATE frame increases the window beyond the persistent limit
  * update to the persistent limit causes a window to become negative

PiperOrigin-RevId: 429071623
diff --git a/http2/adapter/window_manager.cc b/http2/adapter/window_manager.cc
index 9ab661d..76bde18 100644
--- a/http2/adapter/window_manager.cc
+++ b/http2/adapter/window_manager.cc
@@ -19,12 +19,7 @@
   QUICHE_VLOG(2) << "WindowManager@" << this
                  << " OnWindowSizeLimitChange from old limit of " << limit_
                  << " to new limit of " << new_limit;
-  if (new_limit > limit_) {
-    window_ += (new_limit - limit_);
-  } else {
-    QUICHE_BUG(H2 window decrease)
-        << "Window size limit decrease not currently supported.";
-  }
+  window_ += (new_limit - limit_);
   limit_ = new_limit;
 }
 
@@ -68,11 +63,6 @@
 }
 
 void WindowManager::MaybeNotifyListener() {
-  if (buffered_ + window_ > limit_) {
-    QUICHE_LOG(ERROR) << "Flow control violation; limit: " << limit_
-                      << " buffered: " << buffered_ << " window: " << window_;
-    return;
-  }
   // For the sake of efficiency, we want to send window updates if less than
   // half of the max quota is available to the peer at any point in time.
   const int64_t kDesiredMinWindow = limit_ / 2;
diff --git a/http2/adapter/window_manager.h b/http2/adapter/window_manager.h
index a4fe468..f4ee23f 100644
--- a/http2/adapter/window_manager.h
+++ b/http2/adapter/window_manager.h
@@ -50,6 +50,10 @@
     MarkDataFlushed(bytes);
   }
 
+  // Increments the window size without affecting the limit. Useful if this end
+  // of a stream or connection issues a one-time WINDOW_UPDATE.
+  void IncreaseWindow(int64_t delta) { window_ += delta; }
+
  private:
   friend class test::WindowManagerPeer;
 
diff --git a/http2/adapter/window_manager_test.cc b/http2/adapter/window_manager_test.cc
index e81dc94..191ebe9 100644
--- a/http2/adapter/window_manager_test.cc
+++ b/http2/adapter/window_manager_test.cc
@@ -161,6 +161,53 @@
   EXPECT_THAT(call_sequence_, testing::ElementsAre(1));
 }
 
+TEST_F(WindowManagerTest, OnWindowSizeLimitChange) {
+  wm_.MarkDataBuffered(10000);
+  EXPECT_EQ(wm_.CurrentWindowSize(), kDefaultLimit - 10000);
+  EXPECT_EQ(wm_.WindowSizeLimit(), kDefaultLimit);
+
+  wm_.OnWindowSizeLimitChange(kDefaultLimit + 1000);
+  EXPECT_EQ(wm_.CurrentWindowSize(), kDefaultLimit - 9000);
+  EXPECT_EQ(wm_.WindowSizeLimit(), kDefaultLimit + 1000);
+
+  wm_.OnWindowSizeLimitChange(kDefaultLimit - 1000);
+  EXPECT_EQ(wm_.CurrentWindowSize(), kDefaultLimit - 11000);
+  EXPECT_EQ(wm_.WindowSizeLimit(), kDefaultLimit - 1000);
+}
+
+TEST_F(WindowManagerTest, NegativeWindowSize) {
+  wm_.MarkDataBuffered(80000);
+  // 98304 window - 80000 buffered = 18304 available
+  EXPECT_EQ(wm_.CurrentWindowSize(), 18304);
+  wm_.OnWindowSizeLimitChange(65535);
+  // limit decreases by 98304 - 65535 = 32769, window becomes -14465
+  EXPECT_EQ(wm_.CurrentWindowSize(), -14465);
+  wm_.MarkDataFlushed(70000);
+  // Still 10000 bytes buffered, so window manager grants sufficient quota to
+  // reach a window of 65535 - 10000.
+  EXPECT_EQ(wm_.CurrentWindowSize(), 55535);
+  // Desired window minus existing window: 55535 - (-14465) = 70000
+  EXPECT_THAT(call_sequence_, testing::ElementsAre(70000));
+}
+
+TEST_F(WindowManagerTest, IncreaseWindow) {
+  wm_.MarkDataBuffered(1000);
+  EXPECT_EQ(wm_.CurrentWindowSize(), kDefaultLimit - 1000);
+  EXPECT_EQ(wm_.WindowSizeLimit(), kDefaultLimit);
+
+  // Increasing the window beyond the limit is allowed.
+  wm_.IncreaseWindow(5000);
+  EXPECT_EQ(wm_.CurrentWindowSize(), kDefaultLimit + 4000);
+  EXPECT_EQ(wm_.WindowSizeLimit(), kDefaultLimit);
+
+  // 80000 bytes are buffered, then flushed.
+  wm_.MarkWindowConsumed(80000);
+  // The window manager replenishes the consumed quota up to the limit.
+  EXPECT_THAT(call_sequence_, testing::ElementsAre(75000));
+  // The window is the limit, minus buffered data, as expected.
+  EXPECT_EQ(wm_.CurrentWindowSize(), kDefaultLimit - 1000);
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace adapter