hunk.code_window: angular.module('portainer').service('TerminalWindow', function ($window) {
     this.terminalopen = function () {
  
hunk.labels: add keep
hunk.after_edit:   const terminalHeight = 495;
  
hunk.file_path: app/portainer/services/terminal-window.js
hunk.type: add
file: package offlinegate
  
  import (
  	"io"
  	"net/http"
  	"net/http/httptest"
  	"sync"
  	"testing"
  	"time"
  
  	"github.com/stretchr/testify/assert"
  )
  
  func Test_canLockAndUnlock(t *testing.T) {
  	o := NewOfflineGate()
  
  	unlock := o.Lock()
  	unlock()
  }
  
  func Test_hasToBeUnlockedToLockAgain(t *testing.T) {
  	// scenario:
  	// 1. first routine starts and locks the gate
  	// 2. first routine starts a second and wait for the second to start
  	// 3. second start but waits for the gate to be released
  	// 4. first continues and unlocks the gate, when done
  	// 5. second be able to continue
  	// 6. second lock the gate, does the job and unlocks it
  
  	o := NewOfflineGate()
  
  	wg := sync.WaitGroup{}
  	wg.Add(2)
  
  	result := make([]string, 0, 2)
  	go func() {
  		unlock := o.Lock()
  		defer unlock()
  		waitForSecondToStart := sync.WaitGroup{}
  		waitForSecondToStart.Add(1)
  		go func() {
  			waitForSecondToStart.Done()
  			unlock := o.Lock()
  			defer unlock()
  			result = append(result, "second")
  			wg.Done()
  		}()
  		waitForSecondToStart.Wait()
  		result = append(result, "first")
  		wg.Done()
  	}()
  
  	wg.Wait()
  
  	if len(result) != 2 || result[0] != "first" || result[1] != "second" {
  		t.Error("Second call have disresregarded a raised lock")
  	}
  
  }
  
  func Test_waitChannelWillBeEmpty_ifGateIsUnlocked(t *testing.T) {
  	o := NewOfflineGate()
  
  	signalingCh := o.Watch()
  	if signalingCh != nil {
  		t.Error("Signaling channel should be empty")
  	}
  }
  
  func Test_startWaitingForSignal_beforeGateGetsUnlocked(t *testing.T) {
  	// scenario:
  	// 1. main routing locks the gate and waits for a consumer to start up
  	// 2. consumer starts up, notifies main and begins waiting for the gate to be unlocked
  	// 3. main unlocks the gate
  	// 4. consumer be able to continue
  
  	o := NewOfflineGate()
  	unlock := o.Lock()
  
  	signalingCh := o.Watch()
  
  	wg := sync.WaitGroup{}
  	wg.Add(1)
  	readerIsReady := sync.WaitGroup{}
  	readerIsReady.Add(1)
  
  	go func(t *testing.T) {
  		readerIsReady.Done()
  
  		// either wait for a signal or timeout
  		select {
  		case <-signalingCh:
  		case <-time.After(10 * time.Second):
  			t.Error("Failed to wait for a signal, exit by timeout")
  		}
  		wg.Done()
  	}(t)
  
  	readerIsReady.Wait()
  	unlock()
  
  	wg.Wait()
  }
  
  func Test_startWaitingForSignal_afterGateGetsUnlocked(t *testing.T) {
  	// scenario:
  	// 1. main routing locks, gets waiting channel and unlocks
  	// 2. consumer starts up and begins waiting for the gate to be unlocked
  	// 3. consumer gets signal immediately and continues
  
  	o := NewOfflineGate()
  	unlock := o.Lock()
  	signalingCh := o.Watch()
  	unlock()
  
  	wg := sync.WaitGroup{}
  	wg.Add(1)
  
  	go func(t *testing.T) {
  		// either wait for a signal or timeout
  		select {
  		case <-signalingCh:
  		case <-time.After(10 * time.Second):
  			t.Error("Failed to wait for a signal, exit by timeout")
  		}
  		wg.Done()
  	}(t)
  
  	wg.Wait()
  }
  
  func Test_waitingMiddleware_executesImmediately_whenNotLocked(t *testing.T) {
  	// scenario:
  	// 1. create an gate
  	// 2. kick off a waiting middleware that will release immediately as gate wasn't locked
  	// 3. middleware shouldn't timeout
  
  	o := NewOfflineGate()
  
  	request := httptest.NewRequest(http.MethodPost, "/", nil)
  	response := httptest.NewRecorder()
  
  	timeout := 2 * time.Second
  	start := time.Now()
  	o.WaitingMiddleware(timeout, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  		elapsed := time.Since(start)
  		if elapsed >= timeout {
  			t.Error("WaitingMiddleware had likely timeout, when it shouldn't")
  		}
  		w.Write([]byte("success"))
  	})).ServeHTTP(response, request)
  
  	body, _ := io.ReadAll(response.Body)
  	if string(body) != "success" {
  		t.Error("Didn't receive expected result from the hanlder")
  	}
  }
  
  func Test_waitingMiddleware_waitsForTheLockToBeReleased(t *testing.T) {
  	// scenario:
  	// 1. create an gate and lock it
  	// 2. kick off a routing that will unlock the gate after 1 second
  	// 3. kick off a waiting middleware that will wait for lock to be eventually released
  	// 4. middleware shouldn't timeout
  
  	o := NewOfflineGate()
  	unlock := o.Lock()
  
  	request := httptest.NewRequest(http.MethodPost, "/", nil)
  	response := httptest.NewRecorder()
  
  	go func() {
  		time.Sleep(1 * time.Second)
  		unlock()
  	}()
  
  	timeout := 10 * time.Second
  	start := time.Now()
  	o.WaitingMiddleware(timeout, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  		elapsed := time.Since(start)
  		if elapsed >= timeout {
  			t.Error("WaitingMiddleware had likely timeout, when it shouldn't")
  		}
  		w.Write([]byte("success"))
  	})).ServeHTTP(response, request)
  
  	body, _ := io.ReadAll(response.Body)
  	if string(body) != "success" {
  		t.Error("Didn't receive expected result from the hanlder")
  	}
  }
  
  func Test_waitingMiddleware_mayTimeout_whenLockedForTooLong(t *testing.T) {
  	/*
  		scenario:
  		1. create an gate and lock it
  		2. kick off a waiting middleware that will wait for lock to be eventually released
  		3. because we never unlocked the gate, middleware suppose to timeout
  	*/
  	o := NewOfflineGate()
  	o.Lock()
  
  	request := httptest.NewRequest(http.MethodPost, "/", nil)
  	response := httptest.NewRecorder()
  
  	timeout := 1 * time.Second
  	start := time.Now()
  	o.WaitingMiddleware(timeout, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  		elapsed := time.Since(start)
  		if elapsed < timeout {
  			t.Error("WaitingMiddleware suppose to timeout, but it didnt")
  		}
  		w.Write([]byte("success"))
  	})).ServeHTTP(response, request)
  
  	assert.Equal(t, http.StatusRequestTimeout, response.Result().StatusCode, "Request support to timeout waiting for the gate")
  }
  