// Copyright 2018 Google LLC
//
// 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.

//go:build linux
// +build linux

package main_test

// import (
// 	"context"
// 	"crypto/tls"
// 	"crypto/x509"
// 	"errors"
// 	"fmt"
// 	"io/ioutil"
// 	"net"
// 	"net/http"
// 	"net/url"
// 	"os"
// 	"os/exec"
// 	"strings"
// 	"testing"
// 	"time"

// 	"cloud.google.com/go/internal/testutil"
// 	"cloud.google.com/go/storage"
// 	"golang.org/x/oauth2"
// 	"google.golang.org/api/option"
// )

// const initial = "initial state"

// func TestIntegration_HTTPR(t *testing.T) {
// 	if testing.Short() {
// 		t.Skip("Integration tests skipped in short mode")
// 	}
// 	if testutil.ProjID() == "" {
// 		t.Fatal("set GCLOUD_TESTS_GOLANG_PROJECT_ID and GCLOUD_TESTS_GOLANG_KEY")
// 	}
// 	// Get a unique temporary filename.
// 	f, err := ioutil.TempFile("", "httpreplay")
// 	if err != nil {
// 		t.Fatal(err)
// 	}
// 	replayFilename := f.Name()
// 	if err := f.Close(); err != nil {
// 		t.Fatal(err)
// 	}
// 	defer os.Remove(replayFilename)

// 	if err := exec.Command("go", "build").Run(); err != nil {
// 		t.Fatalf("running 'go build': %v", err)
// 	}
// 	defer os.Remove("./httpr")
// 	want := runRecord(t, replayFilename)
// 	got := runReplay(t, replayFilename)
// 	if got != want {
// 		t.Fatalf("got %q, want %q", got, want)
// 	}
// }

// func runRecord(t *testing.T, filename string) string {
// 	cmd, tr, cport, err := start("-record", filename)
// 	if err != nil {
// 		t.Fatal(err)
// 	}
// 	defer stop(t, cmd)

// 	ctx := context.Background()
// 	hc := &http.Client{
// 		Transport: &oauth2.Transport{
// 			Base:   tr,
// 			Source: testutil.TokenSource(ctx, storage.ScopeFullControl),
// 		},
// 	}
// 	res, err := http.Post(
// 		fmt.Sprintf("http://localhost:%s/initial", cport),
// 		"text/plain",
// 		strings.NewReader(initial))
// 	if err != nil {
// 		t.Fatal(err)
// 	}
// 	if res.StatusCode != 200 {
// 		t.Fatalf("from POST: %s", res.Status)
// 	}
// 	info, err := getBucketInfo(ctx, hc)
// 	if err != nil {
// 		t.Fatal(err)
// 	}
// 	return info
// }

// func runReplay(t *testing.T, filename string) string {
// 	cmd, tr, cport, err := start("-replay", filename)
// 	if err != nil {
// 		t.Fatal(err)
// 	}
// 	defer stop(t, cmd)

// 	hc := &http.Client{Transport: tr}
// 	res, err := http.Get(fmt.Sprintf("http://localhost:%s/initial", cport))
// 	if err != nil {
// 		t.Fatal(err)
// 	}
// 	if res.StatusCode != 200 {
// 		t.Fatalf("from GET: %s", res.Status)
// 	}
// 	bytes, err := ioutil.ReadAll(res.Body)
// 	res.Body.Close()
// 	if err != nil {
// 		t.Fatal(err)
// 	}
// 	if got, want := string(bytes), initial; got != want {
// 		t.Errorf("initial: got %q, want %q", got, want)
// 	}
// 	info, err := getBucketInfo(context.Background(), hc)
// 	if err != nil {
// 		t.Fatal(err)
// 	}
// 	return info
// }

// // Start the proxy binary and wait for it to come up.
// // Return a transport that talks to the proxy, as well as the control port.
// // modeFlag must be either "-record" or "-replay".
// func start(modeFlag, filename string) (*exec.Cmd, *http.Transport, string, error) {
// 	pport, err := pickPort()
// 	if err != nil {
// 		return nil, nil, "", err
// 	}
// 	cport, err := pickPort()
// 	if err != nil {
// 		return nil, nil, "", err
// 	}
// 	cmd := exec.Command("./httpr", "-port", pport, "-control-port", cport, modeFlag, filename, "-debug-headers")
// 	if err := cmd.Start(); err != nil {
// 		return nil, nil, "", err
// 	}
// 	// Wait for the server to come up.
// 	serverUp := false
// 	for i := 0; i < 10; i++ {
// 		if conn, err := net.Dial("tcp", "localhost:"+cport); err == nil {
// 			conn.Close()
// 			serverUp = true
// 			break
// 		}
// 		time.Sleep(time.Second)
// 	}
// 	if !serverUp {
// 		return nil, nil, "", errors.New("server never came up")
// 	}
// 	tr, err := proxyTransport(pport, cport)
// 	if err != nil {
// 		return nil, nil, "", err
// 	}
// 	return cmd, tr, cport, nil
// }

// func stop(t *testing.T, cmd *exec.Cmd) {
// 	if err := cmd.Process.Signal(os.Interrupt); err != nil {
// 		t.Fatal(err)
// 	}
// }

// // pickPort picks an unused port.
// func pickPort() (string, error) {
// 	l, err := net.Listen("tcp", ":0")
// 	if err != nil {
// 		return "", err
// 	}
// 	addr := l.Addr().String()
// 	_, port, err := net.SplitHostPort(addr)
// 	if err != nil {
// 		return "", err
// 	}
// 	l.Close()
// 	return port, nil
// }

// func proxyTransport(pport, cport string) (*http.Transport, error) {
// 	caCert, err := getBody(fmt.Sprintf("http://localhost:%s/authority.cer", cport))
// 	if err != nil {
// 		return nil, err
// 	}
// 	caCertPool := x509.NewCertPool()
// 	if !caCertPool.AppendCertsFromPEM([]byte(caCert)) {
// 		return nil, errors.New("bad CA Cert")
// 	}
// 	return &http.Transport{
// 		Proxy:           http.ProxyURL(&url.URL{Host: "localhost:" + pport}),
// 		TLSClientConfig: &tls.Config{RootCAs: caCertPool},
// 	}, nil
// }

// func getBucketInfo(ctx context.Context, hc *http.Client) (string, error) {
// 	client, err := storage.NewClient(ctx, option.WithHTTPClient(hc))
// 	if err != nil {
// 		return "", err
// 	}
// 	defer client.Close()
// 	b := client.Bucket(testutil.ProjID())
// 	attrs, err := b.Attrs(ctx)
// 	if err != nil {
// 		return "", err
// 	}
// 	return fmt.Sprintf("name:%s reqpays:%v location:%s sclass:%s",
// 		attrs.Name, attrs.RequesterPays, attrs.Location, attrs.StorageClass), nil
// }

// func getBody(url string) ([]byte, error) {
// 	res, err := http.Get(url)
// 	if err != nil {
// 		return nil, err
// 	}
// 	if res.StatusCode != 200 {
// 		return nil, fmt.Errorf("response: %s", res.Status)
// 	}
// 	defer res.Body.Close()
// 	return ioutil.ReadAll(res.Body)
// }
