<commit_before>// Copyright 2022 PingCAP, Inc.
//
// 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 isolation_test

import (
	"context"
	"fmt"
	"testing"
	"time"

	"github.com/pingcap/failpoint"
	"github.com/pingcap/tidb/infoschema"
	"github.com/pingcap/tidb/kv"
	"github.com/pingcap/tidb/sessionctx"
	"github.com/pingcap/tidb/sessiontxn"
	"github.com/pingcap/tidb/testkit"
	"github.com/pingcap/tidb/testkit/testfork"
	"github.com/pingcap/tidb/testkit/testsetup"
	"github.com/stretchr/testify/require"
	"github.com/tikv/client-go/v2/oracle"
	"github.com/tikv/client-go/v2/tikv"
	"go.uber.org/goleak"
)

func TestMain(m *testing.M) {
	testsetup.SetupForCommonTest()
	tikv.EnableFailpoints()
	opts := []goleak.Option{
		goleak.IgnoreTopFunction("github.com/golang/glog.(*loggingT).flushDaemon"),
		goleak.IgnoreTopFunction("go.etcd.io/etcd/client/pkg/v3/logutil.(*MergeLogger).outputLoop"),
		goleak.IgnoreTopFunction("go.opencensus.io/stats/view.(*worker).start"),
	}
	goleak.VerifyTestMain(m, opts...)
}

func getOracleTS(t testing.TB, sctx sessionctx.Context) uint64 {
	ts, err := sctx.GetStore().GetOracle().GetTimestamp(context.TODO(), &oracle.Option{TxnScope: oracle.GlobalTxnScope})
	require.NoError(t, err)
	return ts
}

type txnAssert[T sessiontxn.TxnContextProvider] struct {
	sctx                  sessionctx.Context
	isolation             string
	minStartTime          time.Time
	active                bool
	inTxn                 bool
	minStartTS            uint64
	startTS               uint64
	causalConsistencyOnly bool
	couldRetry            bool
}

func (a *txnAssert[T]) Check(t testing.TB) {
	provider := sessiontxn.GetTxnManager(a.sctx).GetContextProvider()
	sessVars := a.sctx.GetSessionVars()
	txnCtx := sessVars.TxnCtx

	if sessVars.SnapshotInfoschema == nil {
		require.Same(t, provider.GetTxnInfoSchema(), txnCtx.InfoSchema)
	} else {
		require.Equal(t, sessVars.SnapshotInfoschema.(infoschema.InfoSchema).SchemaMetaVersion(), provider.GetTxnInfoSchema().SchemaMetaVersion())
	}
	require.Equal(t, a.isolation, txnCtx.Isolation)
	require.Equal(t, a.isolation != "", txnCtx.IsPessimistic)
	require.Equal(t, sessVars.CheckAndGetTxnScope(), txnCtx.TxnScope)
	require.Equal(t, sessVars.ShardAllocateStep, int64(txnCtx.ShardStep))
	require.False(t, txnCtx.IsStaleness)
	require.GreaterOrEqual(t, txnCtx.CreateTime.Nanosecond(), a.minStartTime.Nanosecond())
	require.Equal(t, a.inTxn, sessVars.InTxn())
	require.Equal(t, a.inTxn, txnCtx.IsExplicit)
	require.Equal(t, a.couldRetry, txnCtx.CouldRetry)
	require.Equal(t, assertTxnScope, txnCtx.TxnScope)
	require.Equal(t, assertTxnScope, provider.GetTxnScope())
	require.Equal(t, assertReplicaReadScope, provider.GetReadReplicaScope())

	txn, err := a.sctx.Txn(false)
	require.NoError(t, err)
	require.Equal(t, a.active, txn.Valid())
	if !a.active {
		require.False(t, a.inTxn)
		require.Zero(t, a.startTS)
		require.Zero(t, txnCtx.StartTS)
	} else {
		require.True(t, a.minStartTS != 0 || a.startTS != 0)
		require.Greater(t, txnCtx.StartTS, a.minStartTS)
		if a.startTS != 0 {
			require.Equal(t, a.startTS, txnCtx.StartTS)
		}
		require.Equal(t, txnCtx.StartTS, txn.StartTS())
		require.Same(t, sessVars.KVVars, txn.GetVars())
		require.Equal(t, txnCtx.TxnScope, txn.GetOption(kv.TxnScope))
		require.Equal(t, a.causalConsistencyOnly, !txn.GetOption(kv.GuaranteeLinearizability).(bool))
		require.Equal(t, txnCtx.IsPessimistic, txn.IsPessimistic())
	}
	// The next line is testing the provider has the type T, if not, the cast will panic
	_ = provider.(T)
}

func activeSnapshotTxnAssert(sctx sessionctx.Context, ts uint64, isolation string) *txnAssert[sessiontxn.TxnContextProvider] {
	return &txnAssert[sessiontxn.TxnContextProvider]{
		sctx:         sctx,
		minStartTime: time.Now(),
		startTS:      ts,
		active:       true,
		inTxn:        false,
		isolation:    isolation,
	}
}

func (a *txnAssert[T]) CheckAndGetProvider(t testing.TB) T {
	a.Check(t)
	return sessiontxn.GetTxnManager(a.sctx).GetContextProvider().(T)
}

var assertTxnScope = kv.GlobalTxnScope
var assertReplicaReadScope = kv.GlobalReplicaScope

func forkScopeSettings(t *testfork.T, store kv.Storage) func() {
	tk := testkit.NewTestKit(t, store)
	failPointEnabled := false
	clearFunc := func() {
		assertTxnScope = kv.GlobalTxnScope
		assertReplicaReadScope = kv.GlobalReplicaScope
		tk.MustExec("set @@global.tidb_replica_read='leader'")
		tk.MustExec("set @@global.tidb_enable_local_txn=0")
		if failPointEnabled {
			require.NoError(t, failpoint.Disable("tikvclient/injectTxnScope"))
		}
	}

	clearFunc()
	success := false
	defer func() {
		if !success {
			clearFunc()
		}
	}()

	zone := testfork.PickEnum(t, "", "bj")
	if zone != "" {
		require.NoError(t, failpoint.Enable("tikvclient/injectTxnScope", fmt.Sprintf(`return("%v")`, zone)))
		failPointEnabled = true
		if testfork.PickEnum(t, "", "enableLocalTxn") != "" {
			tk.MustExec("set @@global.tidb_enable_local_txn=1")
			assertTxnScope = zone
			assertReplicaReadScope = zone
		}
	}

	if testfork.PickEnum(t, "", "closetRead") != "" {
		tk.MustExec("set @@global.tidb_replica_read='closest-replicas'")
		if zone != "" {
			assertReplicaReadScope = zone
		}
	}

	success = true
	return clearFunc
}
<commit_msg>*: fix unstable test in `sessiontxn` (#36072)<commit_after>// Copyright 2022 PingCAP, Inc.
//
// 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 isolation_test

import (
	"context"
	"fmt"
	"testing"
	"time"

	"github.com/pingcap/failpoint"
	"github.com/pingcap/tidb/infoschema"
	"github.com/pingcap/tidb/kv"
	"github.com/pingcap/tidb/sessionctx"
	"github.com/pingcap/tidb/sessiontxn"
	"github.com/pingcap/tidb/testkit"
	"github.com/pingcap/tidb/testkit/testfork"
	"github.com/pingcap/tidb/testkit/testsetup"
	"github.com/stretchr/testify/require"
	"github.com/tikv/client-go/v2/oracle"
	"github.com/tikv/client-go/v2/tikv"
	"go.uber.org/goleak"
)

func TestMain(m *testing.M) {
	testsetup.SetupForCommonTest()
	tikv.EnableFailpoints()
	opts := []goleak.Option{
		goleak.IgnoreTopFunction("github.com/golang/glog.(*loggingT).flushDaemon"),
		goleak.IgnoreTopFunction("go.etcd.io/etcd/client/pkg/v3/logutil.(*MergeLogger).outputLoop"),
		goleak.IgnoreTopFunction("go.opencensus.io/stats/view.(*worker).start"),
	}
	goleak.VerifyTestMain(m, opts...)
}

func getOracleTS(t testing.TB, sctx sessionctx.Context) uint64 {
	ts, err := sctx.GetStore().GetOracle().GetTimestamp(context.TODO(), &oracle.Option{TxnScope: oracle.GlobalTxnScope})
	require.NoError(t, err)
	return ts
}

type txnAssert[T sessiontxn.TxnContextProvider] struct {
	sctx                  sessionctx.Context
	isolation             string
	minStartTime          time.Time
	active                bool
	inTxn                 bool
	minStartTS            uint64
	startTS               uint64
	causalConsistencyOnly bool
	couldRetry            bool
}

func (a *txnAssert[T]) Check(t testing.TB) {
	provider := sessiontxn.GetTxnManager(a.sctx).GetContextProvider()
	sessVars := a.sctx.GetSessionVars()
	txnCtx := sessVars.TxnCtx

	if sessVars.SnapshotInfoschema == nil {
		require.Same(t, provider.GetTxnInfoSchema(), txnCtx.InfoSchema)
	} else {
		require.Equal(t, sessVars.SnapshotInfoschema.(infoschema.InfoSchema).SchemaMetaVersion(), provider.GetTxnInfoSchema().SchemaMetaVersion())
	}
	require.Equal(t, a.isolation, txnCtx.Isolation)
	require.Equal(t, a.isolation != "", txnCtx.IsPessimistic)
	require.Equal(t, sessVars.CheckAndGetTxnScope(), txnCtx.TxnScope)
	require.Equal(t, sessVars.ShardAllocateStep, int64(txnCtx.ShardStep))
	require.False(t, txnCtx.IsStaleness)
	require.GreaterOrEqual(t, txnCtx.CreateTime.UnixNano(), a.minStartTime.UnixNano())
	require.Equal(t, a.inTxn, sessVars.InTxn())
	require.Equal(t, a.inTxn, txnCtx.IsExplicit)
	require.Equal(t, a.couldRetry, txnCtx.CouldRetry)
	require.Equal(t, assertTxnScope, txnCtx.TxnScope)
	require.Equal(t, assertTxnScope, provider.GetTxnScope())
	require.Equal(t, assertReplicaReadScope, provider.GetReadReplicaScope())

	txn, err := a.sctx.Txn(false)
	require.NoError(t, err)
	require.Equal(t, a.active, txn.Valid())
	if !a.active {
		require.False(t, a.inTxn)
		require.Zero(t, a.startTS)
		require.Zero(t, txnCtx.StartTS)
	} else {
		require.True(t, a.minStartTS != 0 || a.startTS != 0)
		require.Greater(t, txnCtx.StartTS, a.minStartTS)
		if a.startTS != 0 {
			require.Equal(t, a.startTS, txnCtx.StartTS)
		}
		require.Equal(t, txnCtx.StartTS, txn.StartTS())
		require.Same(t, sessVars.KVVars, txn.GetVars())
		require.Equal(t, txnCtx.TxnScope, txn.GetOption(kv.TxnScope))
		require.Equal(t, a.causalConsistencyOnly, !txn.GetOption(kv.GuaranteeLinearizability).(bool))
		require.Equal(t, txnCtx.IsPessimistic, txn.IsPessimistic())
	}
	// The next line is testing the provider has the type T, if not, the cast will panic
	_ = provider.(T)
}

func activeSnapshotTxnAssert(sctx sessionctx.Context, ts uint64, isolation string) *txnAssert[sessiontxn.TxnContextProvider] {
	return &txnAssert[sessiontxn.TxnContextProvider]{
		sctx:         sctx,
		minStartTime: time.Now(),
		startTS:      ts,
		active:       true,
		inTxn:        false,
		isolation:    isolation,
	}
}

func (a *txnAssert[T]) CheckAndGetProvider(t testing.TB) T {
	a.Check(t)
	return sessiontxn.GetTxnManager(a.sctx).GetContextProvider().(T)
}

var assertTxnScope = kv.GlobalTxnScope
var assertReplicaReadScope = kv.GlobalReplicaScope

func forkScopeSettings(t *testfork.T, store kv.Storage) func() {
	tk := testkit.NewTestKit(t, store)
	failPointEnabled := false
	clearFunc := func() {
		assertTxnScope = kv.GlobalTxnScope
		assertReplicaReadScope = kv.GlobalReplicaScope
		tk.MustExec("set @@global.tidb_replica_read='leader'")
		tk.MustExec("set @@global.tidb_enable_local_txn=0")
		if failPointEnabled {
			require.NoError(t, failpoint.Disable("tikvclient/injectTxnScope"))
		}
	}

	clearFunc()
	success := false
	defer func() {
		if !success {
			clearFunc()
		}
	}()

	zone := testfork.PickEnum(t, "", "bj")
	if zone != "" {
		require.NoError(t, failpoint.Enable("tikvclient/injectTxnScope", fmt.Sprintf(`return("%v")`, zone)))
		failPointEnabled = true
		if testfork.PickEnum(t, "", "enableLocalTxn") != "" {
			tk.MustExec("set @@global.tidb_enable_local_txn=1")
			assertTxnScope = zone
			assertReplicaReadScope = zone
		}
	}

	if testfork.PickEnum(t, "", "closetRead") != "" {
		tk.MustExec("set @@global.tidb_replica_read='closest-replicas'")
		if zone != "" {
			assertReplicaReadScope = zone
		}
	}

	success = true
	return clearFunc
}
<|endoftext|>


<commit_before>// Copyright © 2016 Mark Bates <mark@markbates.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package generate

import (
	"fmt"
	"os/exec"

	"github.com/markbates/gentronics"
	"github.com/spf13/cobra"
)

var publicLogo = &gentronics.RemoteFile{
	File:       gentronics.NewFile("public/assets/images/logo.svg", ""),
	RemotePath: "https://raw.githubusercontent.com/gobuffalo/buffalo/master/logo.svg",
}

var assetsLogo = &gentronics.RemoteFile{
	File:       gentronics.NewFile("assets/images/logo.svg", ""),
	RemotePath: "https://raw.githubusercontent.com/gobuffalo/buffalo/master/logo.svg",
}

// WebpackCmd generates a new actions/resource file and a stub test.
var WebpackCmd = &cobra.Command{
	Use:   "webpack",
	Short: "Generates a webpack asset pipeline.",
	RunE: func(cmd *cobra.Command, args []string) error {
		data := gentronics.Data{
			"withWebpack": true,
		}
		return NewWebpackGenerator(data).Run(".", data)
	},
}

// NewWebpackGenerator generates a new actions/resource file and a stub test.
func NewWebpackGenerator(data gentronics.Data) *gentronics.Generator {
	g := gentronics.New()

	should := func(data gentronics.Data) bool {
		if b, ok := data["withWebpack"]; ok {
			return b.(bool)
		}
		return false
	}

	// if we're not using web pack save the logo and return
	if !should(data) {
		g.Add(publicLogo)
		g.Add(gentronics.NewFile("public/assets/application.js", ""))
		g.Add(gentronics.NewFile("public/assets/application.css", nwApplicationCSS))
		return g
	}

	// if there's no npm, return!
	_, err := exec.LookPath("npm")
	if err != nil {
		fmt.Println("Could not find npm/node. Skipping webpack generation.")
		g.Add(publicLogo)
		return g
	}

	g.Should = should
	g.Add(assetsLogo)
	g.Add(gentronics.NewFile("webpack.config.js", nWebpack))
	g.Add(gentronics.NewFile("public/assets/.gitignore", ""))
	g.Add(gentronics.NewFile("assets/js/application.js", wApplicationJS))
	g.Add(gentronics.NewFile("assets/css/application.scss", wApplicationCSS))
	c := gentronics.NewCommand(exec.Command("npm", "install", "webpack", "-g"))
	g.Add(c)
	c = gentronics.NewCommand(exec.Command("npm", "init", "-y"))
	g.Add(c)

	modules := []string{"webpack", "sass-loader", "css-loader", "style-loader", "node-sass",
		"babel-loader", "extract-text-webpack-plugin", "babel", "babel-core", "url-loader", "file-loader",
		"jquery", "bootstrap", "path", "font-awesome", "npm-install-webpack-plugin", "jquery-ujs",
		"copy-webpack-plugin",
	}
	args := []string{"install", "--save"}
	args = append(args, modules...)
	g.Add(gentronics.NewCommand(exec.Command("npm", args...)))
	return g
}

var nWebpack = `var webpack = require("webpack");
var CopyWebpackPlugin = require('copy-webpack-plugin');
var ExtractTextPlugin = require("extract-text-webpack-plugin");

module.exports = {
  entry: [
    "./assets/js/application.js",
    "./assets/css/application.scss",
    "./node_modules/jquery-ujs/src/rails.js"
  ],
  output: {
    filename: "application.js",
    path: "./public/assets"
  },
  plugins: [
    new webpack.ProvidePlugin({
      $: "jquery",
      jQuery: "jquery"
    }),
    new ExtractTextPlugin("application.css"),
    new CopyWebpackPlugin([{
      from: "./assets",
      to: ""
    }], {
      ignore: [
        "css/*",
        "js/*",
      ]
    })
  ],
  module: {
    loaders: [{
      test: /\.jsx?$/,
      loader: "babel",
      exclude: /node_modules/
    }, {
      test: /\.scss$/,
      loader: ExtractTextPlugin.extract(
        "style",
        "css?sourceMap!sass?sourceMap"
      )
    }, {
      test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
      loader: "url?limit=10000&mimetype=application/font-woff"
    }, {
      test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
      loader: "url?limit=10000&mimetype=application/font-woff"
    }, {
      test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
      loader: "url?limit=10000&mimetype=application/octet-stream"
    }, {
      test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
      loader: "file"
    }, {
      test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
      loader: "url?limit=10000&mimetype=image/svg+xml"
    }]
  }
};
`

const wApplicationJS = `require("bootstrap/dist/js/bootstrap.js");

$(() => {

});`
const wApplicationCSS = `@import "~bootstrap/dist/css/bootstrap.css";
@import "~font-awesome/css/font-awesome.css";
`

const nwApplicationCSS = `* {
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    box-sizing: border-box;
}

body {
    font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
    font-size: 14px;
    line-height: 1.42857143;
    color: #333;
    background-color: #fff;
    margin: 0;
}

h1, h2 {
    margin-top: 20px;
    margin-bottom: 10px;
    font-family: inherit;
    font-weight: 500;
    line-height: 1.1;
    color: inherit;
}

h1 {
    font-size: 36px;
}

h2 {
    font-size: 30px;
}

hr {
    margin-top: 20px;
    margin-bottom: 20px;
    border: 0;
    border-top: 1px solid #eee;
    height: 0;
    -webkit-box-sizing: content-box;
    -moz-box-sizing: content-box;
    box-sizing: content-box;
}

a {
    color: #337ab7;
    text-decoration: none;
}

a:hover {
    color: #23527c;
}

.container {
    padding-right: 15px;
    padding-left: 15px;
    margin-right: auto;
    margin-left: auto;
}

@media (min-width: 768px) {
  .container {
    width: 750px;
  }
}
@media (min-width: 992px) {
  .container {
    width: 970px;
  }
}
@media (min-width: 1200px) {
  .container {
    width: 1170px;
  }
}

.table {
    width: 100%;
    max-width: 100%;
    margin-bottom: 20px;
    background-color: transparent;
    border-spacing: 0;
    border-collapse: collapse;
}

.table-striped > tbody {
    background-color: #f9f9f9;
}

.table > thead > tr > th, .table > tbody > tr > td {
    padding: 8px;
    line-height: 1.42857143;
    vertical-align: top;
    border-top: 1px solid #ddd;
}

.table > thead > tr > th {
    border-top: 0;
    vertical-align: bottom;
    border-bottom: 2px solid #ddd;
    text-align: left;
}

code {
    padding: 2px 4px;
    font-size: 90%;
    color: #c7254e;
    background-color: #f9f2f4;
    border-radius: 4px;
    font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
}

.row {
    margin-right: -15px;
    margin-left: -15px;
}

.col-md-2, .col-md-10 {
    float: left;
    position: relative;
    min-height: 1px;
    padding-right: 15px;
    padding-left: 15px;
}

.col-md-2 {
    width: 16.66666667%;
}

.col-md-10 {
    width: 83.33333333%;
}

img {
    vertical-align: middle;
    border: 0;
}
`
<commit_msg>point people to npm docs if there is an issue running npm<commit_after>// Copyright © 2016 Mark Bates <mark@markbates.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package generate

import (
	"fmt"
	"os/exec"

	"github.com/markbates/gentronics"
	"github.com/spf13/cobra"
)

var publicLogo = &gentronics.RemoteFile{
	File:       gentronics.NewFile("public/assets/images/logo.svg", ""),
	RemotePath: "https://raw.githubusercontent.com/gobuffalo/buffalo/master/logo.svg",
}

var assetsLogo = &gentronics.RemoteFile{
	File:       gentronics.NewFile("assets/images/logo.svg", ""),
	RemotePath: "https://raw.githubusercontent.com/gobuffalo/buffalo/master/logo.svg",
}

// WebpackCmd generates a new actions/resource file and a stub test.
var WebpackCmd = &cobra.Command{
	Use:   "webpack",
	Short: "Generates a webpack asset pipeline.",
	RunE: func(cmd *cobra.Command, args []string) error {
		data := gentronics.Data{
			"withWebpack": true,
		}
		return NewWebpackGenerator(data).Run(".", data)
	},
}

// NewWebpackGenerator generates a new actions/resource file and a stub test.
func NewWebpackGenerator(data gentronics.Data) *gentronics.Generator {
	g := gentronics.New()

	should := func(data gentronics.Data) bool {
		if b, ok := data["withWebpack"]; ok {
			return b.(bool)
		}
		return false
	}

	// if we're not using web pack save the logo and return
	if !should(data) {
		g.Add(publicLogo)
		g.Add(gentronics.NewFile("public/assets/application.js", ""))
		g.Add(gentronics.NewFile("public/assets/application.css", nwApplicationCSS))
		return g
	}

	// if there's no npm, return!
	_, err := exec.LookPath("npm")
	if err != nil {
		fmt.Println("Could not find npm/node. Skipping webpack generation.")
		g.Add(publicLogo)
		return g
	}

	g.Should = should
	g.Add(assetsLogo)
	g.Add(gentronics.NewFile("webpack.config.js", nWebpack))
	g.Add(gentronics.NewFile("public/assets/.gitignore", ""))
	g.Add(gentronics.NewFile("assets/js/application.js", wApplicationJS))
	g.Add(gentronics.NewFile("assets/css/application.scss", wApplicationCSS))

	c := gentronics.NewCommand(exec.Command("npm", "install", "webpack", "-g"))
	rf := gentronics.RunFn(func(path string, data gentronics.Data) error {
		err := c.Run(path, data)
		if err != nil {
			u := "https://docs.npmjs.com/getting-started/fixing-npm-permissions"
			fmt.Printf("There was a problem running npm install. You may want to checkout their docs for help!\n%s\n", u)
			return err
		}
		return nil
	})
	g.Add(&gentronics.Func{
		Runner: rf,
		Should: should,
	})

	c = gentronics.NewCommand(exec.Command("npm", "init", "-y"))
	g.Add(c)

	modules := []string{"webpack", "sass-loader", "css-loader", "style-loader", "node-sass",
		"babel-loader", "extract-text-webpack-plugin", "babel", "babel-core", "url-loader", "file-loader",
		"jquery", "bootstrap", "path", "font-awesome", "npm-install-webpack-plugin", "jquery-ujs",
		"copy-webpack-plugin",
	}
	args := []string{"install", "--save"}
	args = append(args, modules...)
	g.Add(gentronics.NewCommand(exec.Command("npm", args...)))
	return g
}

var nWebpack = `var webpack = require("webpack");
var CopyWebpackPlugin = require('copy-webpack-plugin');
var ExtractTextPlugin = require("extract-text-webpack-plugin");

module.exports = {
  entry: [
    "./assets/js/application.js",
    "./assets/css/application.scss",
    "./node_modules/jquery-ujs/src/rails.js"
  ],
  output: {
    filename: "application.js",
    path: "./public/assets"
  },
  plugins: [
    new webpack.ProvidePlugin({
      $: "jquery",
      jQuery: "jquery"
    }),
    new ExtractTextPlugin("application.css"),
    new CopyWebpackPlugin([{
      from: "./assets",
      to: ""
    }], {
      ignore: [
        "css/*",
        "js/*",
      ]
    })
  ],
  module: {
    loaders: [{
      test: /\.jsx?$/,
      loader: "babel",
      exclude: /node_modules/
    }, {
      test: /\.scss$/,
      loader: ExtractTextPlugin.extract(
        "style",
        "css?sourceMap!sass?sourceMap"
      )
    }, {
      test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
      loader: "url?limit=10000&mimetype=application/font-woff"
    }, {
      test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
      loader: "url?limit=10000&mimetype=application/font-woff"
    }, {
      test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
      loader: "url?limit=10000&mimetype=application/octet-stream"
    }, {
      test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
      loader: "file"
    }, {
      test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
      loader: "url?limit=10000&mimetype=image/svg+xml"
    }]
  }
};
`

const wApplicationJS = `require("bootstrap/dist/js/bootstrap.js");

$(() => {

});`
const wApplicationCSS = `@import "~bootstrap/dist/css/bootstrap.css";
@import "~font-awesome/css/font-awesome.css";
`

const nwApplicationCSS = `* {
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    box-sizing: border-box;
}

body {
    font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
    font-size: 14px;
    line-height: 1.42857143;
    color: #333;
    background-color: #fff;
    margin: 0;
}

h1, h2 {
    margin-top: 20px;
    margin-bottom: 10px;
    font-family: inherit;
    font-weight: 500;
    line-height: 1.1;
    color: inherit;
}

h1 {
    font-size: 36px;
}

h2 {
    font-size: 30px;
}

hr {
    margin-top: 20px;
    margin-bottom: 20px;
    border: 0;
    border-top: 1px solid #eee;
    height: 0;
    -webkit-box-sizing: content-box;
    -moz-box-sizing: content-box;
    box-sizing: content-box;
}

a {
    color: #337ab7;
    text-decoration: none;
}

a:hover {
    color: #23527c;
}

.container {
    padding-right: 15px;
    padding-left: 15px;
    margin-right: auto;
    margin-left: auto;
}

@media (min-width: 768px) {
  .container {
    width: 750px;
  }
}
@media (min-width: 992px) {
  .container {
    width: 970px;
  }
}
@media (min-width: 1200px) {
  .container {
    width: 1170px;
  }
}

.table {
    width: 100%;
    max-width: 100%;
    margin-bottom: 20px;
    background-color: transparent;
    border-spacing: 0;
    border-collapse: collapse;
}

.table-striped > tbody {
    background-color: #f9f9f9;
}

.table > thead > tr > th, .table > tbody > tr > td {
    padding: 8px;
    line-height: 1.42857143;
    vertical-align: top;
    border-top: 1px solid #ddd;
}

.table > thead > tr > th {
    border-top: 0;
    vertical-align: bottom;
    border-bottom: 2px solid #ddd;
    text-align: left;
}

code {
    padding: 2px 4px;
    font-size: 90%;
    color: #c7254e;
    background-color: #f9f2f4;
    border-radius: 4px;
    font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
}

.row {
    margin-right: -15px;
    margin-left: -15px;
}

.col-md-2, .col-md-10 {
    float: left;
    position: relative;
    min-height: 1px;
    padding-right: 15px;
    padding-left: 15px;
}

.col-md-2 {
    width: 16.66666667%;
}

.col-md-10 {
    width: 83.33333333%;
}

img {
    vertical-align: middle;
    border: 0;
}
`
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"net/http"
	"strconv"

	"github.com/julienschmidt/httprouter"
	"github.com/satori/go.uuid"
)

/* Read functions
 */
func GetHostDeployment(w http.ResponseWriter, r *http.Request,
	params httprouter.Params) {
	defer PanicCatcher(w)
	var (
		err     error
		assetid int64
	)

	if _, err = uuid.FromString(params.ByName("system")); err != nil {
		DispatchBadRequest(&w, err)
		return
	}
	if assetid, err = strconv.ParseInt(params.ByName("assetid"), 10, 64); err != nil {
		DispatchBadRequest(&w, err)
		return
	}

	returnChannel := make(chan somaResult)
	handler := handlerMap["hostDeploymentHandler"].(somaHostDeploymentHandler)
	handler.input <- somaHostDeploymentRequest{
		action:  "get",
		reply:   returnChannel,
		system:  params.ByName("system"),
		assetid: assetid,
	}
	result := <-returnChannel
	SendHostDeploymentReply(&w, &result)
}

func AssembleHostUpdate(w http.ResponseWriter, r *http.Request,
	params httprouter.Params) {
	defer PanicCatcher(w)
	var (
		err     error
		assetid int64
	)

	if _, err = uuid.FromString(params.ByName("system")); err != nil {
		DispatchBadRequest(&w, err)
		return
	}
	if assetid, err = strconv.ParseInt(params.ByName("assetid"), 10, 64); err != nil {
		DispatchBadRequest(&w, err)
		return
	}

	cReq := proto.Request{}
	if err = DecodeJsonBody(r, &cReq); err != nil {
		DispatchBadRequest(&w, err)
		return
	}

	if cReq.HostDeployment == nil {
		DispatchBadRequest(&w, err)
		return
	}

	returnChannel := make(chan somaResult)
	handler := handlerMap["hostDeploymentHandler"].(somaHostDeploymentHandler)
	handler.input <- somaHostDeploymentRequest{
		action:  "assemble",
		reply:   returnChannel,
		system:  params.ByName("system"),
		assetid: assetid,
		idlist:  cReq.HostDeployment.CurrentCheckInstanceIdList,
	}
	result := <-returnChannel
	SendHostDeploymentReply(&w, &result)
}

/* Utility
 */
func SendHostDeploymentReply(w *http.ResponseWriter, r *somaResult) {
	result := proto.NewHostDeploymentResult()
	if r.MarkErrors(&result) {
		goto dispatch
	}
	for _, i := range (*r).HostDeployments {
		if i.Delete {
			*result.HostDeployments = append(*result.HostDeployments, proto.HostDeployment{
				DeleteInstance:  true,
				CheckInstanceId: i.DeleteId,
			})
			continue
		}
		*result.Deployments = append(*result.Deployments, i.Deployment)
	}

dispatch:
	json, err := json.Marshal(result)
	if err != nil {
		DispatchInternalError(w, err)
		return
	}
	DispatchJsonReply(w, &json)
	return
}

// vim: ts=4 sw=4 sts=4 noet fenc=utf-8 ffs=unix
<commit_msg>Send better error message than nil<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"

	"github.com/julienschmidt/httprouter"
	"github.com/satori/go.uuid"
)

/* Read functions
 */
func GetHostDeployment(w http.ResponseWriter, r *http.Request,
	params httprouter.Params) {
	defer PanicCatcher(w)
	var (
		err     error
		assetid int64
	)

	if _, err = uuid.FromString(params.ByName("system")); err != nil {
		DispatchBadRequest(&w, err)
		return
	}
	if assetid, err = strconv.ParseInt(params.ByName("assetid"), 10, 64); err != nil {
		DispatchBadRequest(&w, err)
		return
	}

	returnChannel := make(chan somaResult)
	handler := handlerMap["hostDeploymentHandler"].(somaHostDeploymentHandler)
	handler.input <- somaHostDeploymentRequest{
		action:  "get",
		reply:   returnChannel,
		system:  params.ByName("system"),
		assetid: assetid,
	}
	result := <-returnChannel
	SendHostDeploymentReply(&w, &result)
}

func AssembleHostUpdate(w http.ResponseWriter, r *http.Request,
	params httprouter.Params) {
	defer PanicCatcher(w)
	var (
		err     error
		assetid int64
	)

	if _, err = uuid.FromString(params.ByName("system")); err != nil {
		DispatchBadRequest(&w, err)
		return
	}
	if assetid, err = strconv.ParseInt(params.ByName("assetid"), 10, 64); err != nil {
		DispatchBadRequest(&w, err)
		return
	}

	cReq := proto.Request{}
	if err = DecodeJsonBody(r, &cReq); err != nil {
		DispatchBadRequest(&w, err)
		return
	}

	if cReq.HostDeployment == nil {
		DispatchBadRequest(&w, fmt.Errorf(`HostDeployment section missing`))
		return
	}

	returnChannel := make(chan somaResult)
	handler := handlerMap["hostDeploymentHandler"].(somaHostDeploymentHandler)
	handler.input <- somaHostDeploymentRequest{
		action:  "assemble",
		reply:   returnChannel,
		system:  params.ByName("system"),
		assetid: assetid,
		idlist:  cReq.HostDeployment.CurrentCheckInstanceIdList,
	}
	result := <-returnChannel
	SendHostDeploymentReply(&w, &result)
}

/* Utility
 */
func SendHostDeploymentReply(w *http.ResponseWriter, r *somaResult) {
	result := proto.NewHostDeploymentResult()
	if r.MarkErrors(&result) {
		goto dispatch
	}
	for _, i := range (*r).HostDeployments {
		if i.Delete {
			*result.HostDeployments = append(*result.HostDeployments, proto.HostDeployment{
				DeleteInstance:  true,
				CheckInstanceId: i.DeleteId,
			})
			continue
		}
		*result.Deployments = append(*result.Deployments, i.Deployment)
	}

dispatch:
	json, err := json.Marshal(result)
	if err != nil {
		DispatchInternalError(w, err)
		return
	}
	DispatchJsonReply(w, &json)
	return
}

// vim: ts=4 sw=4 sts=4 noet fenc=utf-8 ffs=unix
<|endoftext|>


<commit_before>/* https://leetcode.com/problems/majority-element/#/description
Given an array of size n, find the majority element. The majority element is the element that appears more than ⌊ n/2 ⌋ times.

You may assume that the array is non-empty and the majority element always exist in the array.

Credits:
Special thanks to @ts for adding this problem and creating all test cases.
*/

package leetcode

func majorityElement(nums []int) int {
	maps := make(map[int]int)
	mid := len(nums) / 2
	for i := 0; i < len(nums); i++ {
		if v, ok := maps[nums[i]]; ok {
			v += 1
			maps[nums[i]] = v
		} else {
			maps[nums[i]] = 1
		}
		if v, ok := maps[nums[i]]; ok && v > mid {
			return nums[i]
		}
	}
	panic("nums cannot be empty")
}
<commit_msg>don't use hash table<commit_after>/* https://leetcode.com/problems/majority-element/#/description
Given an array of size n, find the majority element. The majority element is the element that appears more than ⌊ n/2 ⌋ times.

You may assume that the array is non-empty and the majority element always exist in the array.

Credits:
Special thanks to @ts for adding this problem and creating all test cases.
*/

package leetcode

func majorityElement(nums []int) int {
	/*maps := make(map[int]int)
	  mid := len(nums) / 2
	  for i := 0; i < len(nums); i++ {
	      if v, ok := maps[nums[i]]; ok {
	          v += 1
	          maps[nums[i]] = v
	      } else {
	          maps[nums[i]t ] = 1
	      }
	      if v, ok := maps[nums[i]]; ok && v > mid {
	          return nums[i]
	      }
	  }
	  panic("nums cannot be empty")
	*/
	cur, count := nums[0], 1
	for i := 1; i < len(nums); i++ {
		if count == 0 {
			count = 1
			cur = nums[i]
		} else if cur == nums[i] {
			count++
		} else {
			count--
		}
	}
	return cur
}
<|endoftext|>


<commit_before>/* https://leetcode.com/problems/partition-list/description/
Given a linked list and a value x, partition it such that all nodes less than x come before nodes greater than or equal to x.

You should preserve the original relative order of the nodes in each of the two partitions.

For example,
Given 1->4->3->2->5->2 and x = 3,
return 1->2->2->4->3->5.
*/

package leetcode

func partition(head *ListNode, x int) *ListNode {
	ltHead, gtHead := &ListNode{Val: 0}, &ListNode{Val: 0}
	ltCur, gtCur := ltHead, gtHead

	for cur := head; cur != nil; cur = cur.Next {
		tmp := &ListNode{Val: cur.Val}
		if cur.Val < x {
			ltCur.Next, ltCur = tmp, tmp
		} else {
			gtCur.Next, gtCur = tmp, tmp
		}
	}
	ltCur.Next = gtHead.Next
	return ltHead.Next
}
<commit_msg>fix var name<commit_after>/* https://leetcode.com/problems/partition-list/description/
Given a linked list and a value x, partition it such that all nodes less than x come before nodes greater than or equal to x.

You should preserve the original relative order of the nodes in each of the two partitions.

For example,
Given 1->4->3->2->5->2 and x = 3,
return 1->2->2->4->3->5.
*/

package leetcode

func partition(head *ListNode, x int) *ListNode {
	ltHead, gteHead := &ListNode{Val: 0}, &ListNode{Val: 0}
	ltCur, gteCur := ltHead, gteHead

	for cur := head; cur != nil; cur = cur.Next {
		tmp := &ListNode{Val: cur.Val}
		if cur.Val < x {
			ltCur.Next, ltCur = tmp, tmp
		} else {
			gteCur.Next, gteCur = tmp, tmp
		}
	}
	ltCur.Next = gteHead.Next
	return ltHead.Next
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors.

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 e2e_node

import (
	"flag"
	"fmt"
	"io/ioutil"
	"math/rand"
	"net/http"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"reflect"
	"strconv"
	"strings"
	"syscall"
	"time"

	"github.com/golang/glog"
)

var serverStartTimeout = flag.Duration("server-start-timeout", time.Second*120, "Time to wait for each server to become healthy.")
var reportDir = flag.String("report-dir", "", "Path to the directory where the JUnit XML reports should be saved. Default is empty, which doesn't generate these reports.")

type e2eService struct {
	killCmds []*killCmd
	rmDirs   []string

	etcdDataDir         string
	kubeletStaticPodDir string
	nodeName            string
	logFiles            map[string]logFileData
	cgroupsPerQOS       bool
}

type logFileData struct {
	files             []string
	journalctlCommand []string
}

const (
	// This is consistent with the level used in a cluster e2e test.
	LOG_VERBOSITY_LEVEL = "4"
)

func newE2eService(nodeName string, cgroupsPerQOS bool) *e2eService {
	// Special log files that need to be collected for additional debugging.
	var logFiles = map[string]logFileData{
		"kern.log":   {[]string{"/var/log/kern.log"}, []string{"-k"}},
		"docker.log": {[]string{"/var/log/docker.log", "/var/log/upstart/docker.log"}, []string{"-u", "docker"}},
	}

	return &e2eService{
		nodeName:      nodeName,
		logFiles:      logFiles,
		cgroupsPerQOS: cgroupsPerQOS,
	}
}

func (es *e2eService) start() error {
	if _, err := getK8sBin("kubelet"); err != nil {
		return err
	}
	if _, err := getK8sBin("kube-apiserver"); err != nil {
		return err
	}

	cmd, err := es.startEtcd()
	if err != nil {
		return err
	}
	es.killCmds = append(es.killCmds, cmd)
	es.rmDirs = append(es.rmDirs, es.etcdDataDir)

	cmd, err = es.startApiServer()
	if err != nil {
		return err
	}
	es.killCmds = append(es.killCmds, cmd)

	cmd, err = es.startKubeletServer()
	if err != nil {
		return err
	}
	es.killCmds = append(es.killCmds, cmd)
	es.rmDirs = append(es.rmDirs, es.kubeletStaticPodDir)

	return nil
}

// Get logs of interest either via journalctl or by creating sym links.
// Since we scp files from the remote directory, symlinks will be treated as normal files and file contents will be copied over.
func (es *e2eService) getLogFiles() {
	// Nothing to do if report dir is not specified.
	if *reportDir == "" {
		return
	}
	journaldFound := isJournaldAvailable()
	for targetFileName, logFileData := range es.logFiles {
		targetLink := path.Join(*reportDir, targetFileName)
		if journaldFound {
			// Skip log files that do not have an equivalent in journald based machines.
			if len(logFileData.journalctlCommand) == 0 {
				continue
			}
			out, err := exec.Command("sudo", append([]string{"journalctl"}, logFileData.journalctlCommand...)...).CombinedOutput()
			if err != nil {
				glog.Errorf("failed to get %q from journald: %v, %v", targetFileName, string(out), err)
			} else {
				if err = ioutil.WriteFile(targetLink, out, 0755); err != nil {
					glog.Errorf("failed to write logs to %q: %v", targetLink, err)
				}
			}
			continue
		}
		for _, file := range logFileData.files {
			if _, err := os.Stat(file); err != nil {
				// Expected file not found on this distro.
				continue
			}
			if err := copyLogFile(file, targetLink); err != nil {
				glog.Error(err)
			} else {
				break
			}
		}
	}
}

func copyLogFile(src, target string) error {
	// If not a journald based distro, then just symlink files.
	if out, err := exec.Command("sudo", "cp", src, target).CombinedOutput(); err != nil {
		return fmt.Errorf("failed to copy %q to %q: %v, %v", src, target, out, err)
	}
	if out, err := exec.Command("sudo", "chmod", "a+r", target).CombinedOutput(); err != nil {
		return fmt.Errorf("failed to make log file %q world readable: %v, %v", target, out, err)
	}
	return nil
}

func isJournaldAvailable() bool {
	_, err := exec.LookPath("journalctl")
	return err == nil
}

func (es *e2eService) stop() {
	for _, k := range es.killCmds {
		if err := k.Kill(); err != nil {
			glog.Errorf("Failed to stop %v: %v", k.name, err)
		}
	}
	for _, d := range es.rmDirs {
		err := os.RemoveAll(d)
		if err != nil {
			glog.Errorf("Failed to delete directory %s.\n%v", d, err)
		}
	}
}

func (es *e2eService) startEtcd() (*killCmd, error) {
	dataDir, err := ioutil.TempDir("", "node-e2e")
	if err != nil {
		return nil, err
	}
	es.etcdDataDir = dataDir
	cmd := exec.Command("etcd")
	// Execute etcd in the data directory instead of using --data-dir because the flag sometimes requires additional
	// configuration (e.g. --name in version 0.4.9)
	cmd.Dir = es.etcdDataDir
	hcc := newHealthCheckCommand(
		"http://127.0.0.1:4001/v2/keys/", // Trailing slash is required,
		cmd,
		"etcd.log")
	return &killCmd{name: "etcd", cmd: cmd}, es.startServer(hcc)
}

func (es *e2eService) startApiServer() (*killCmd, error) {
	cmd := exec.Command("sudo", getApiServerBin(),
		"--etcd-servers", "http://127.0.0.1:4001",
		"--insecure-bind-address", "0.0.0.0",
		"--service-cluster-ip-range", "10.0.0.1/24",
		"--kubelet-port", "10250",
		"--allow-privileged", "true",
		"--v", LOG_VERBOSITY_LEVEL, "--logtostderr",
	)
	hcc := newHealthCheckCommand(
		"http://127.0.0.1:8080/healthz",
		cmd,
		"kube-apiserver.log")
	return &killCmd{name: "kube-apiserver", cmd: cmd}, es.startServer(hcc)
}

func (es *e2eService) startKubeletServer() (*killCmd, error) {
	dataDir, err := ioutil.TempDir("", "node-e2e-pod")
	if err != nil {
		return nil, err
	}
	es.kubeletStaticPodDir = dataDir
	var killOverride *exec.Cmd
	cmdArgs := []string{}
	if systemdRun, err := exec.LookPath("systemd-run"); err == nil {
		// On systemd services, detection of a service / unit works reliably while
		// detection of a process started from an ssh session does not work.
		// Since kubelet will typically be run as a service it also makes more
		// sense to test it that way
		unitName := fmt.Sprintf("kubelet-%d.service", rand.Int31())
		cmdArgs = append(cmdArgs, systemdRun, "--unit="+unitName, getKubeletServerBin())
		killOverride = exec.Command("sudo", "systemctl", "kill", unitName)
		es.logFiles["kubelet.log"] = logFileData{
			journalctlCommand: []string{"-u", unitName},
		}
	} else {
		cmdArgs = append(cmdArgs, getKubeletServerBin())
	}
	cmdArgs = append(cmdArgs,
		"--api-servers", "http://127.0.0.1:8080",
		"--address", "0.0.0.0",
		"--port", "10250",
		"--hostname-override", es.nodeName, // Required because hostname is inconsistent across hosts
		"--volume-stats-agg-period", "10s", // Aggregate volumes frequently so tests don't need to wait as long
		"--allow-privileged", "true",
		"--serialize-image-pulls", "false",
		"--config", es.kubeletStaticPodDir,
		"--file-check-frequency", "10s", // Check file frequently so tests won't wait too long
		"--v", LOG_VERBOSITY_LEVEL, "--logtostderr",
		"--pod-cidr=10.180.0.0/24", // Assign a fixed CIDR to the node because there is no node controller.
	)
	if es.cgroupsPerQOS {
		cmdArgs = append(cmdArgs,
			"--cgroups-per-qos", "true",
			"--cgroup-root", "/",
		)
	}
	if !*disableKubenet {
		cwd, err := os.Getwd()
		if err != nil {
			return nil, err
		}
		cmdArgs = append(cmdArgs,
			"--network-plugin=kubenet",
			"--network-plugin-dir", filepath.Join(cwd, CNIDirectory, "bin")) // Enable kubenet
	}

	cmd := exec.Command("sudo", cmdArgs...)
	hcc := newHealthCheckCommand(
		"http://127.0.0.1:10255/healthz",
		cmd,
		"kubelet.log")
	return &killCmd{name: "kubelet", cmd: cmd, override: killOverride}, es.startServer(hcc)
}

func (es *e2eService) startServer(cmd *healthCheckCommand) error {
	cmdErrorChan := make(chan error)
	go func() {
		defer close(cmdErrorChan)

		// Create the output filename
		outPath := path.Join(*reportDir, cmd.outputFilename)
		outfile, err := os.Create(outPath)
		if err != nil {
			cmdErrorChan <- fmt.Errorf("Failed to create file %s for `%s` %v.", outPath, cmd, err)
			return
		}
		defer outfile.Close()
		defer outfile.Sync()

		// Set the command to write the output file
		cmd.Cmd.Stdout = outfile
		cmd.Cmd.Stderr = outfile

		// Killing the sudo command should kill the server as well.
		attrs := &syscall.SysProcAttr{}
		// Hack to set linux-only field without build tags.
		deathSigField := reflect.ValueOf(attrs).Elem().FieldByName("Pdeathsig")
		if deathSigField.IsValid() {
			deathSigField.Set(reflect.ValueOf(syscall.SIGKILL))
		} else {
			cmdErrorChan <- fmt.Errorf("Failed to set Pdeathsig field (non-linux build)")
			return
		}
		cmd.Cmd.SysProcAttr = attrs

		// Run the command
		err = cmd.Run()
		if err != nil {
			cmdErrorChan <- fmt.Errorf("%s Failed with error \"%v\".  Output written to: %s", cmd, err, outPath)
			return
		}
	}()

	endTime := time.Now().Add(*serverStartTimeout)
	for endTime.After(time.Now()) {
		select {
		case err := <-cmdErrorChan:
			return err
		case <-time.After(time.Second):
			resp, err := http.Get(cmd.HealthCheckUrl)
			if err == nil && resp.StatusCode == http.StatusOK {
				return nil
			}
		}
	}
	return fmt.Errorf("Timeout waiting for service %s", cmd)
}

// killCmd is a struct to kill a given cmd. The cmd member specifies a command
// to find the pid of and attempt to kill.
// If the override field is set, that will be used instead to kill the command.
// name is only used for logging
type killCmd struct {
	name     string
	cmd      *exec.Cmd
	override *exec.Cmd
}

func (k *killCmd) Kill() error {
	name := k.name
	cmd := k.cmd

	if k.override != nil {
		return k.override.Run()
	}

	if cmd == nil {
		return fmt.Errorf("Could not kill %s because both `override` and `cmd` are nil", name)
	}

	if cmd.Process == nil {
		glog.V(2).Infof("%s not running", name)
		return nil
	}
	pid := cmd.Process.Pid
	if pid <= 1 {
		return fmt.Errorf("invalid PID %d for %s", pid, name)
	}

	// Attempt to shut down the process in a friendly manner before forcing it.
	waitChan := make(chan error)
	go func() {
		_, err := cmd.Process.Wait()
		waitChan <- err
		close(waitChan)
	}()

	const timeout = 10 * time.Second
	for _, signal := range []string{"-TERM", "-KILL"} {
		glog.V(2).Infof("Killing process %d (%s) with %s", pid, name, signal)
		_, err := exec.Command("sudo", "kill", signal, strconv.Itoa(pid)).Output()
		if err != nil {
			glog.Errorf("Error signaling process %d (%s) with %s: %v", pid, name, signal, err)
			continue
		}

		select {
		case err := <-waitChan:
			if err != nil {
				return fmt.Errorf("error stopping %s: %v", name, err)
			}
			// Success!
			return nil
		case <-time.After(timeout):
			// Continue.
		}
	}

	return fmt.Errorf("unable to stop %s", name)
}

type healthCheckCommand struct {
	*exec.Cmd
	HealthCheckUrl string
	outputFilename string
}

func newHealthCheckCommand(healthCheckUrl string, cmd *exec.Cmd, filename string) *healthCheckCommand {
	return &healthCheckCommand{
		HealthCheckUrl: healthCheckUrl,
		Cmd:            cmd,
		outputFilename: filename,
	}
}

func (hcc *healthCheckCommand) String() string {
	return fmt.Sprintf("`%s` health-check: %s", strings.Join(append([]string{hcc.Path}, hcc.Args[1:]...), " "), hcc.HealthCheckUrl)
}
<commit_msg>Change process group when sending kill signal<commit_after>/*
Copyright 2016 The Kubernetes Authors.

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 e2e_node

import (
	"flag"
	"fmt"
	"io/ioutil"
	"math/rand"
	"net/http"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"reflect"
	"strconv"
	"strings"
	"syscall"
	"time"

	"github.com/golang/glog"
)

var serverStartTimeout = flag.Duration("server-start-timeout", time.Second*120, "Time to wait for each server to become healthy.")
var reportDir = flag.String("report-dir", "", "Path to the directory where the JUnit XML reports should be saved. Default is empty, which doesn't generate these reports.")

type e2eService struct {
	killCmds []*killCmd
	rmDirs   []string

	etcdDataDir         string
	kubeletStaticPodDir string
	nodeName            string
	logFiles            map[string]logFileData
	cgroupsPerQOS       bool
}

type logFileData struct {
	files             []string
	journalctlCommand []string
}

const (
	// This is consistent with the level used in a cluster e2e test.
	LOG_VERBOSITY_LEVEL = "4"
)

func newE2eService(nodeName string, cgroupsPerQOS bool) *e2eService {
	// Special log files that need to be collected for additional debugging.
	var logFiles = map[string]logFileData{
		"kern.log":   {[]string{"/var/log/kern.log"}, []string{"-k"}},
		"docker.log": {[]string{"/var/log/docker.log", "/var/log/upstart/docker.log"}, []string{"-u", "docker"}},
	}

	return &e2eService{
		nodeName:      nodeName,
		logFiles:      logFiles,
		cgroupsPerQOS: cgroupsPerQOS,
	}
}

func (es *e2eService) start() error {
	if _, err := getK8sBin("kubelet"); err != nil {
		return err
	}
	if _, err := getK8sBin("kube-apiserver"); err != nil {
		return err
	}

	cmd, err := es.startEtcd()
	if err != nil {
		return err
	}
	es.killCmds = append(es.killCmds, cmd)
	es.rmDirs = append(es.rmDirs, es.etcdDataDir)

	cmd, err = es.startApiServer()
	if err != nil {
		return err
	}
	es.killCmds = append(es.killCmds, cmd)

	cmd, err = es.startKubeletServer()
	if err != nil {
		return err
	}
	es.killCmds = append(es.killCmds, cmd)
	es.rmDirs = append(es.rmDirs, es.kubeletStaticPodDir)

	return nil
}

// Get logs of interest either via journalctl or by creating sym links.
// Since we scp files from the remote directory, symlinks will be treated as normal files and file contents will be copied over.
func (es *e2eService) getLogFiles() {
	// Nothing to do if report dir is not specified.
	if *reportDir == "" {
		return
	}
	journaldFound := isJournaldAvailable()
	for targetFileName, logFileData := range es.logFiles {
		targetLink := path.Join(*reportDir, targetFileName)
		if journaldFound {
			// Skip log files that do not have an equivalent in journald based machines.
			if len(logFileData.journalctlCommand) == 0 {
				continue
			}
			out, err := exec.Command("sudo", append([]string{"journalctl"}, logFileData.journalctlCommand...)...).CombinedOutput()
			if err != nil {
				glog.Errorf("failed to get %q from journald: %v, %v", targetFileName, string(out), err)
			} else {
				if err = ioutil.WriteFile(targetLink, out, 0755); err != nil {
					glog.Errorf("failed to write logs to %q: %v", targetLink, err)
				}
			}
			continue
		}
		for _, file := range logFileData.files {
			if _, err := os.Stat(file); err != nil {
				// Expected file not found on this distro.
				continue
			}
			if err := copyLogFile(file, targetLink); err != nil {
				glog.Error(err)
			} else {
				break
			}
		}
	}
}

func copyLogFile(src, target string) error {
	// If not a journald based distro, then just symlink files.
	if out, err := exec.Command("sudo", "cp", src, target).CombinedOutput(); err != nil {
		return fmt.Errorf("failed to copy %q to %q: %v, %v", src, target, out, err)
	}
	if out, err := exec.Command("sudo", "chmod", "a+r", target).CombinedOutput(); err != nil {
		return fmt.Errorf("failed to make log file %q world readable: %v, %v", target, out, err)
	}
	return nil
}

func isJournaldAvailable() bool {
	_, err := exec.LookPath("journalctl")
	return err == nil
}

func (es *e2eService) stop() {
	for _, k := range es.killCmds {
		if err := k.Kill(); err != nil {
			glog.Errorf("Failed to stop %v: %v", k.name, err)
		}
	}
	for _, d := range es.rmDirs {
		err := os.RemoveAll(d)
		if err != nil {
			glog.Errorf("Failed to delete directory %s.\n%v", d, err)
		}
	}
}

func (es *e2eService) startEtcd() (*killCmd, error) {
	dataDir, err := ioutil.TempDir("", "node-e2e")
	if err != nil {
		return nil, err
	}
	es.etcdDataDir = dataDir
	cmd := exec.Command("etcd")
	// Execute etcd in the data directory instead of using --data-dir because the flag sometimes requires additional
	// configuration (e.g. --name in version 0.4.9)
	cmd.Dir = es.etcdDataDir
	hcc := newHealthCheckCommand(
		"http://127.0.0.1:4001/v2/keys/", // Trailing slash is required,
		cmd,
		"etcd.log")
	return &killCmd{name: "etcd", cmd: cmd}, es.startServer(hcc)
}

func (es *e2eService) startApiServer() (*killCmd, error) {
	cmd := exec.Command("sudo", getApiServerBin(),
		"--etcd-servers", "http://127.0.0.1:4001",
		"--insecure-bind-address", "0.0.0.0",
		"--service-cluster-ip-range", "10.0.0.1/24",
		"--kubelet-port", "10250",
		"--allow-privileged", "true",
		"--v", LOG_VERBOSITY_LEVEL, "--logtostderr",
	)
	hcc := newHealthCheckCommand(
		"http://127.0.0.1:8080/healthz",
		cmd,
		"kube-apiserver.log")
	return &killCmd{name: "kube-apiserver", cmd: cmd}, es.startServer(hcc)
}

func (es *e2eService) startKubeletServer() (*killCmd, error) {
	dataDir, err := ioutil.TempDir("", "node-e2e-pod")
	if err != nil {
		return nil, err
	}
	es.kubeletStaticPodDir = dataDir
	var killOverride *exec.Cmd
	cmdArgs := []string{}
	if systemdRun, err := exec.LookPath("systemd-run"); err == nil {
		// On systemd services, detection of a service / unit works reliably while
		// detection of a process started from an ssh session does not work.
		// Since kubelet will typically be run as a service it also makes more
		// sense to test it that way
		unitName := fmt.Sprintf("kubelet-%d.service", rand.Int31())
		cmdArgs = append(cmdArgs, systemdRun, "--unit="+unitName, getKubeletServerBin())
		killOverride = exec.Command("sudo", "systemctl", "kill", unitName)
		es.logFiles["kubelet.log"] = logFileData{
			journalctlCommand: []string{"-u", unitName},
		}
	} else {
		cmdArgs = append(cmdArgs, getKubeletServerBin())
	}
	cmdArgs = append(cmdArgs,
		"--api-servers", "http://127.0.0.1:8080",
		"--address", "0.0.0.0",
		"--port", "10250",
		"--hostname-override", es.nodeName, // Required because hostname is inconsistent across hosts
		"--volume-stats-agg-period", "10s", // Aggregate volumes frequently so tests don't need to wait as long
		"--allow-privileged", "true",
		"--serialize-image-pulls", "false",
		"--config", es.kubeletStaticPodDir,
		"--file-check-frequency", "10s", // Check file frequently so tests won't wait too long
		"--v", LOG_VERBOSITY_LEVEL, "--logtostderr",
		"--pod-cidr=10.180.0.0/24", // Assign a fixed CIDR to the node because there is no node controller.
	)
	if es.cgroupsPerQOS {
		cmdArgs = append(cmdArgs,
			"--cgroups-per-qos", "true",
			"--cgroup-root", "/",
		)
	}
	if !*disableKubenet {
		cwd, err := os.Getwd()
		if err != nil {
			return nil, err
		}
		cmdArgs = append(cmdArgs,
			"--network-plugin=kubenet",
			"--network-plugin-dir", filepath.Join(cwd, CNIDirectory, "bin")) // Enable kubenet
	}

	cmd := exec.Command("sudo", cmdArgs...)
	hcc := newHealthCheckCommand(
		"http://127.0.0.1:10255/healthz",
		cmd,
		"kubelet.log")
	return &killCmd{name: "kubelet", cmd: cmd, override: killOverride}, es.startServer(hcc)
}

func (es *e2eService) startServer(cmd *healthCheckCommand) error {
	cmdErrorChan := make(chan error)
	go func() {
		defer close(cmdErrorChan)

		// Create the output filename
		outPath := path.Join(*reportDir, cmd.outputFilename)
		outfile, err := os.Create(outPath)
		if err != nil {
			cmdErrorChan <- fmt.Errorf("Failed to create file %s for `%s` %v.", outPath, cmd, err)
			return
		}
		defer outfile.Close()
		defer outfile.Sync()

		// Set the command to write the output file
		cmd.Cmd.Stdout = outfile
		cmd.Cmd.Stderr = outfile

		// Killing the sudo command should kill the server as well.
		attrs := &syscall.SysProcAttr{}
		// Hack to set linux-only field without build tags.
		deathSigField := reflect.ValueOf(attrs).Elem().FieldByName("Pdeathsig")
		if deathSigField.IsValid() {
			deathSigField.Set(reflect.ValueOf(syscall.SIGKILL))
		} else {
			cmdErrorChan <- fmt.Errorf("Failed to set Pdeathsig field (non-linux build)")
			return
		}
		cmd.Cmd.SysProcAttr = attrs

		// Run the command
		err = cmd.Run()
		if err != nil {
			cmdErrorChan <- fmt.Errorf("%s Failed with error \"%v\".  Output written to: %s", cmd, err, outPath)
			return
		}
	}()

	endTime := time.Now().Add(*serverStartTimeout)
	for endTime.After(time.Now()) {
		select {
		case err := <-cmdErrorChan:
			return err
		case <-time.After(time.Second):
			resp, err := http.Get(cmd.HealthCheckUrl)
			if err == nil && resp.StatusCode == http.StatusOK {
				return nil
			}
		}
	}
	return fmt.Errorf("Timeout waiting for service %s", cmd)
}

// killCmd is a struct to kill a given cmd. The cmd member specifies a command
// to find the pid of and attempt to kill.
// If the override field is set, that will be used instead to kill the command.
// name is only used for logging
type killCmd struct {
	name     string
	cmd      *exec.Cmd
	override *exec.Cmd
}

func (k *killCmd) Kill() error {
	name := k.name
	cmd := k.cmd

	if k.override != nil {
		return k.override.Run()
	}

	if cmd == nil {
		return fmt.Errorf("Could not kill %s because both `override` and `cmd` are nil", name)
	}

	if cmd.Process == nil {
		glog.V(2).Infof("%s not running", name)
		return nil
	}
	pid := cmd.Process.Pid
	if pid <= 1 {
		return fmt.Errorf("invalid PID %d for %s", pid, name)
	}

	// Attempt to shut down the process in a friendly manner before forcing it.
	waitChan := make(chan error)
	go func() {
		_, err := cmd.Process.Wait()
		waitChan <- err
		close(waitChan)
	}()

	const timeout = 10 * time.Second
	for _, signal := range []string{"-TERM", "-KILL"} {
		glog.V(2).Infof("Killing process %d (%s) with %s", pid, name, signal)
		cmd := exec.Command("sudo", "kill", signal, strconv.Itoa(pid))
		// Run the 'kill' command in a separate process group so sudo doesn't ignore it
		cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
		_, err := cmd.Output()
		if err != nil {
			glog.Errorf("Error signaling process %d (%s) with %s: %v", pid, name, signal, err)
			continue
		}

		select {
		case err := <-waitChan:
			if err != nil {
				return fmt.Errorf("error stopping %s: %v", name, err)
			}
			// Success!
			return nil
		case <-time.After(timeout):
			// Continue.
		}
	}

	return fmt.Errorf("unable to stop %s", name)
}

type healthCheckCommand struct {
	*exec.Cmd
	HealthCheckUrl string
	outputFilename string
}

func newHealthCheckCommand(healthCheckUrl string, cmd *exec.Cmd, filename string) *healthCheckCommand {
	return &healthCheckCommand{
		HealthCheckUrl: healthCheckUrl,
		Cmd:            cmd,
		outputFilename: filename,
	}
}

func (hcc *healthCheckCommand) String() string {
	return fmt.Sprintf("`%s` health-check: %s", strings.Join(append([]string{hcc.Path}, hcc.Args[1:]...), " "), hcc.HealthCheckUrl)
}
<|endoftext|>


<commit_before>// compile

// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package p

// any is now permitted instead of interface{}
var x any
<commit_msg>test/fixedbugs: adjust test case (fix longtest builders)<commit_after>// compile -G=3

// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package p

// any is now permitted instead of interface{}
var x any
<|endoftext|>


<commit_before>// 11 february 2014
//package ui
package main

import (
	"syscall"
	"unsafe"
	"runtime"
)

var uitask chan *uimsg

type uimsg struct {
	call		*syscall.LazyProc
	p		[]uintptr
	ret		chan uiret
}

type uiret struct {
	ret		uintptr
	err		error
}

func ui(initDone chan error) {
	runtime.LockOSThread()

	uitask = make(chan *uimsg)
	initDone <- doWindowsInit()

	for m := range uitask {
		r1, _, err := m.msg.Call(m.p...)
		m.ret <- uiret{
			ret:	r1,
			err:	err,
		}
	}
}
<commit_msg>Added the Windows message loop.<commit_after>// 11 february 2014
//package ui
package main

import (
	"fmt"
	"syscall"
	"unsafe"
	"runtime"
)

var uitask chan *uimsg

type uimsg struct {
	call		*syscall.LazyProc
	p		[]uintptr
	ret		chan uiret
}

type uiret struct {
	ret		uintptr
	err		error
}

func ui(initDone chan error) {
	runtime.LockOSThread()

	uitask = make(chan *uimsg)
	initDone <- doWindowsInit()

	go msgloop()

	for m := range uitask {
		r1, _, err := m.msg.Call(m.p...)
		m.ret <- uiret{
			ret:	r1,
			err:	err,
		}
	}
}

var (
	_dispatchMessage = user32.NewProc("DispatchMessageW")
	_getMessage = user32.NewProc("GetMessageW")
	_postQuitMessage = user32.NewProc("PostQuitMessage")
	_sendMessage = user32.NewProc("SendMessageW")
	_translateMessage = user32.NewProc("TranslateMessage")
)

func msgloop() {
	var msg struct {
		Hwnd	_HWND
		Message	uint32
		WParam	_WPARAM
		LParam	_LPARAM
		Time		uint32
		Pt		_POINT
	}

	for {
		r1, _, err := getMessage.Call(
			uintptr(unsafe.Pointer(&msg)),
			uintptr(_NULL),
			uintptr(0),
			uintptr(0))
		if r1 == uintptr(getMessageFail) {		// failure
			panic(fmt.Sprintf("GetMessage failed: %v", err))
		} else if r1 == 0 {	// quit
			break
		}
		// TODO handle potential errors in TranslateMessage() and DispatchMessage()
		_translateMessage.Call(uintptr(unsafe.Pointer(&msg)))
		_dispatchMessage.Call(uintptr(unsafe.Pointer(&msg)))
	}
}
<|endoftext|>


<commit_before>package sdp

import (
	"testing"
)

const (
	BaseSDP = "v=0\r\n" +
		"o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n" +
		"s=SDP Seminar\r\n"

	SessionInformationSDP = BaseSDP +
		"i=A Seminar on the session description protocol\r\n" +
		"t=3034423619 3042462419\r\n"

	URISDP = BaseSDP +
		"u=http://www.example.com/seminars/sdp.pdf\r\n" +
		"t=3034423619 3042462419\r\n"

	EmailAddressSDP = BaseSDP +
		"e=j.doe@example.com (Jane Doe)\r\n" +
		"t=3034423619 3042462419\r\n"

	PhoneNumberSDP = BaseSDP +
		"p=+1 617 555-6011\r\n" +
		"t=3034423619 3042462419\r\n"

	SessionConnectionInformationSDP = BaseSDP +
		"c=IN IP4 224.2.17.12/127\r\n" +
		"t=3034423619 3042462419\r\n"

	SessionBandwidthSDP = BaseSDP +
		"b=X-YZ:128\r\n" +
		"b=AS:12345\r\n" +
		"t=3034423619 3042462419\r\n"

	TimingSDP = BaseSDP +
		"t=2873397496 2873404696\r\n"

	// Short hand time notation is converted into NTP timestamp format in
	// seconds. Because of that unittest comparisons will fail as the same time
	// will be expressed in different units.
	RepeatTimesSDP = TimingSDP +
		"r=604800 3600 0 90000\r\n" +
		"r=3d 2h 0 21h\r\n"

	RepeatTimesSDPExpected = TimingSDP +
		"r=604800 3600 0 90000\r\n" +
		"r=259200 7200 0 75600\r\n"

	// The expected value looks a bit different for the same reason as mentioned
	// above regarding RepeatTimes.
	TimeZonesSDP = TimingSDP +
		"r=2882844526 -1h 2898848070 0\r\n"

	TimeZonesSDPExpected = TimingSDP +
		"r=2882844526 -3600 2898848070 0\r\n"

	SessionEncryptionKeySDP = TimingSDP +
		"k=prompt\r\n"

	SessionAttributesSDP = TimingSDP +
		"a=rtpmap:96 opus/48000\r\n"

	MediaNameSDP = TimingSDP +
		"m=video 51372 RTP/AVP 99\r\n" +
		"m=audio 54400 RTP/SAVPF 0 96\r\n"

	MediaTitleSDP = MediaNameSDP +
		"i=Vivamus a posuere nisl\r\n"

	MediaConnectionInformationSDP = MediaNameSDP +
		"c=IN IP4 203.0.113.1\r\n"

	MediaBandwidthSDP = MediaNameSDP +
		"b=X-YZ:128\r\n" +
		"b=AS:12345\r\n"

	MediaEncryptionKeySDP = MediaNameSDP +
		"k=prompt\r\n"

	MediaAttributesSDP = MediaNameSDP +
		"a=rtpmap:99 h263-1998/90000\r\n" +
		"a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ host\r\n"

	CanonicalUnmarshalSDP = "v=0\r\n" +
		"o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n" +
		"s=SDP Seminar\r\n" +
		"i=A Seminar on the session description protocol\r\n" +
		"u=http://www.example.com/seminars/sdp.pdf\r\n" +
		"e=j.doe@example.com (Jane Doe)\r\n" +
		"p=+1 617 555-6011\r\n" +
		"c=IN IP4 224.2.17.12/127\r\n" +
		"b=X-YZ:128\r\n" +
		"b=AS:12345\r\n" +
		"t=2873397496 2873404696\r\n" +
		"t=3034423619 3042462419\r\n" +
		"r=604800 3600 0 90000\r\n" +
		"z=2882844526 -3600 2898848070 0\r\n" +
		"k=prompt\r\n" +
		"a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ host\r\n" +
		"a=recvonly\r\n" +
		"m=audio 49170 RTP/AVP 0\r\n" +
		"i=Vivamus a posuere nisl\r\n" +
		"c=IN IP4 203.0.113.1\r\n" +
		"b=X-YZ:128\r\n" +
		"k=prompt\r\n" +
		"a=sendrecv\r\n" +
		"m=video 51372 RTP/AVP 99\r\n" +
		"a=rtpmap:99 h263-1998/90000\r\n"
)

func TestUnmarshalSessionInformation(t *testing.T) {
	sd := &SessionDescription{}
	if err := sd.Unmarshal(SessionInformationSDP); err != nil {
		t.Errorf("error: %v", err)
	}

	actual := sd.Marshal()
	if actual != SessionInformationSDP {
		t.Errorf("error:\n\nEXPECTED:\n%v\nACTUAL:\n%v", SessionInformationSDP, actual)
	}
}

func TestUnmarshalURI(t *testing.T) {
	sd := &SessionDescription{}
	if err := sd.Unmarshal(URISDP); err != nil {
		t.Errorf("error: %v", err)
	}

	actual := sd.Marshal()
	if actual != URISDP {
		t.Errorf("error:\n\nEXPECTED:\n%v\nACTUAL:\n%v", URISDP, actual)
	}
}

func TestUnmarshalEmailAddress(t *testing.T) {
	sd := &SessionDescription{}
	if err := sd.Unmarshal(EmailAddressSDP); err != nil {
		t.Errorf("error: %v", err)
	}

	actual := sd.Marshal()
	if actual != EmailAddressSDP {
		t.Errorf("error:\n\nEXPECTED:\n%v\nACTUAL:\n%v", EmailAddressSDP, actual)
	}
}

func TestUnmarshalPhoneNumber(t *testing.T) {
	sd := &SessionDescription{}
	if err := sd.Unmarshal(PhoneNumberSDP); err != nil {
		t.Errorf("error: %v", err)
	}

	actual := sd.Marshal()
	if actual != PhoneNumberSDP {
		t.Errorf("error:\n\nEXPECTED:\n%v\nACTUAL:\n%v", PhoneNumberSDP, actual)
	}
}

func TestUnmarshalSessionConnectionInformation(t *testing.T) {
	sd := &SessionDescription{}
	if err := sd.Unmarshal(SessionConnectionInformationSDP); err != nil {
		t.Errorf("error: %v", err)
	}

	actual := sd.Marshal()
	if actual != SessionConnectionInformationSDP {
		t.Errorf("error:\n\nEXPECTED:\n%v\nACTUAL:\n%v", SessionConnectionInformationSDP, actual)
	}
}

func TestUnmarshalSessionBandwidth(t *testing.T) {
	sd := &SessionDescription{}
	if err := sd.Unmarshal(SessionBandwidthSDP); err != nil {
		t.Errorf("error: %v", err)
	}

	actual := sd.Marshal()
	if actual != SessionBandwidthSDP {
		t.Errorf("error:\n\nEXPECTED:\n%v\nACTUAL:\n%v", SessionBandwidthSDP, actual)
	}
}

func TestUnmarshalRepeatTimes(t *testing.T) {
	sd := &SessionDescription{}
	if err := sd.Unmarshal(RepeatTimesSDP); err != nil {
		t.Errorf("error: %v", err)
	}

	actual := sd.Marshal()
	if actual != RepeatTimesSDPExpected {
		t.Errorf("error:\n\nEXPECTED:\n%v\nACTUAL:\n%v", RepeatTimesSDPExpected, actual)
	}
}

func TestUnmarshalTimeZones(t *testing.T) {
	sd := &SessionDescription{}
	if err := sd.Unmarshal(TimeZonesSDP); err != nil {
		t.Errorf("error: %v", err)
	}

	actual := sd.Marshal()
	if actual != TimeZonesSDPExpected {
		t.Errorf("error:\n\nEXPECTED:\n%v\nACTUAL:\n%v", TimeZonesSDPExpected, actual)
	}
}

func TestUnmarshalSessionEncryptionKey(t *testing.T) {
	sd := &SessionDescription{}
	if err := sd.Unmarshal(SessionEncryptionKeySDP); err != nil {
		t.Errorf("error: %v", err)
	}

	actual := sd.Marshal()
	if actual != SessionEncryptionKeySDP {
		t.Errorf("error:\n\nEXPECTED:\n%v\nACTUAL:\n%v", SessionEncryptionKeySDP, actual)
	}
}

func TestUnmarshalSessionAttributes(t *testing.T) {
	sd := &SessionDescription{}
	if err := sd.Unmarshal(SessionAttributesSDP); err != nil {
		t.Errorf("error: %v", err)
	}

	actual := sd.Marshal()
	if actual != SessionAttributesSDP {
		t.Errorf("error:\n\nEXPECTED:\n%v\nACTUAL:\n%v", SessionAttributesSDP, actual)
	}
}

func TestUnmarshalMediaName(t *testing.T) {
	sd := &SessionDescription{}
	if err := sd.Unmarshal(MediaNameSDP); err != nil {
		t.Errorf("error: %v", err)
	}

	actual := sd.Marshal()
	if actual != MediaNameSDP {
		t.Errorf("error:\n\nEXPECTED:\n%v\nACTUAL:\n%v", MediaNameSDP, actual)
	}
}

func TestUnmarshalMediaTitle(t *testing.T) {
	sd := &SessionDescription{}
	if err := sd.Unmarshal(MediaTitleSDP); err != nil {
		t.Errorf("error: %v", err)
	}

	actual := sd.Marshal()
	if actual != MediaTitleSDP {
		t.Errorf("error:\n\nEXPECTED:\n%v\nACTUAL:\n%v", MediaTitleSDP, actual)
	}
}

func TestUnmarshalMediaConnectionInformation(t *testing.T) {
	sd := &SessionDescription{}
	if err := sd.Unmarshal(MediaConnectionInformationSDP); err != nil {
		t.Errorf("error: %v", err)
	}

	actual := sd.Marshal()
	if actual != MediaConnectionInformationSDP {
		t.Errorf("error:\n\nEXPECTED:\n%v\nACTUAL:\n%v", MediaConnectionInformationSDP, actual)
	}
}

func TestUnmarshalMediaBandwidth(t *testing.T) {
	sd := &SessionDescription{}
	if err := sd.Unmarshal(MediaBandwidthSDP); err != nil {
		t.Errorf("error: %v", err)
	}

	actual := sd.Marshal()
	if actual != MediaBandwidthSDP {
		t.Errorf("error:\n\nEXPECTED:\n%v\nACTUAL:\n%v", MediaBandwidthSDP, actual)
	}
}

func TestUnmarshalMediaEncryptionKey(t *testing.T) {
	sd := &SessionDescription{}
	if err := sd.Unmarshal(MediaEncryptionKeySDP); err != nil {
		t.Errorf("error: %v", err)
	}

	actual := sd.Marshal()
	if actual != MediaEncryptionKeySDP {
		t.Errorf("error:\n\nEXPECTED:\n%v\nACTUAL:\n%v", MediaEncryptionKeySDP, actual)
	}
}

func TestUnmarshalMediaAttributes(t *testing.T) {
	sd := &SessionDescription{}
	if err := sd.Unmarshal(MediaAttributesSDP); err != nil {
		t.Errorf("error: %v", err)
	}

	actual := sd.Marshal()
	if actual != MediaAttributesSDP {
		t.Errorf("error:\n\nEXPECTED:\n%v\nACTUAL:\n%v", MediaAttributesSDP, actual)
	}
}

func TestUnmarshalCanonical(t *testing.T) {
	sd := &SessionDescription{}
	if err := sd.Unmarshal(CanonicalUnmarshalSDP); err != nil {
		t.Errorf("error: %v", err)
	}

	actual := sd.Marshal()
	if actual != CanonicalUnmarshalSDP {
		t.Errorf("error:\n\nEXPECTED:\n%v\nACTUAL:\n%v", CanonicalUnmarshalSDP, actual)
	}
}
<commit_msg>Refactor into table-driven tests<commit_after>package sdp

import (
	"testing"
)

const (
	BaseSDP = "v=0\r\n" +
		"o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n" +
		"s=SDP Seminar\r\n"

	SessionInformationSDP = BaseSDP +
		"i=A Seminar on the session description protocol\r\n" +
		"t=3034423619 3042462419\r\n"

	URISDP = BaseSDP +
		"u=http://www.example.com/seminars/sdp.pdf\r\n" +
		"t=3034423619 3042462419\r\n"

	EmailAddressSDP = BaseSDP +
		"e=j.doe@example.com (Jane Doe)\r\n" +
		"t=3034423619 3042462419\r\n"

	PhoneNumberSDP = BaseSDP +
		"p=+1 617 555-6011\r\n" +
		"t=3034423619 3042462419\r\n"

	SessionConnectionInformationSDP = BaseSDP +
		"c=IN IP4 224.2.17.12/127\r\n" +
		"t=3034423619 3042462419\r\n"

	SessionBandwidthSDP = BaseSDP +
		"b=X-YZ:128\r\n" +
		"b=AS:12345\r\n" +
		"t=3034423619 3042462419\r\n"

	TimingSDP = BaseSDP +
		"t=2873397496 2873404696\r\n"

	// Short hand time notation is converted into NTP timestamp format in
	// seconds. Because of that unittest comparisons will fail as the same time
	// will be expressed in different units.
	RepeatTimesSDP = TimingSDP +
		"r=604800 3600 0 90000\r\n" +
		"r=3d 2h 0 21h\r\n"

	RepeatTimesSDPExpected = TimingSDP +
		"r=604800 3600 0 90000\r\n" +
		"r=259200 7200 0 75600\r\n"

	// The expected value looks a bit different for the same reason as mentioned
	// above regarding RepeatTimes.
	TimeZonesSDP = TimingSDP +
		"r=2882844526 -1h 2898848070 0\r\n"

	TimeZonesSDPExpected = TimingSDP +
		"r=2882844526 -3600 2898848070 0\r\n"

	SessionEncryptionKeySDP = TimingSDP +
		"k=prompt\r\n"

	SessionAttributesSDP = TimingSDP +
		"a=rtpmap:96 opus/48000\r\n"

	MediaNameSDP = TimingSDP +
		"m=video 51372 RTP/AVP 99\r\n" +
		"m=audio 54400 RTP/SAVPF 0 96\r\n"

	MediaTitleSDP = MediaNameSDP +
		"i=Vivamus a posuere nisl\r\n"

	MediaConnectionInformationSDP = MediaNameSDP +
		"c=IN IP4 203.0.113.1\r\n"

	MediaBandwidthSDP = MediaNameSDP +
		"b=X-YZ:128\r\n" +
		"b=AS:12345\r\n"

	MediaEncryptionKeySDP = MediaNameSDP +
		"k=prompt\r\n"

	MediaAttributesSDP = MediaNameSDP +
		"a=rtpmap:99 h263-1998/90000\r\n" +
		"a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ host\r\n"

	CanonicalUnmarshalSDP = "v=0\r\n" +
		"o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n" +
		"s=SDP Seminar\r\n" +
		"i=A Seminar on the session description protocol\r\n" +
		"u=http://www.example.com/seminars/sdp.pdf\r\n" +
		"e=j.doe@example.com (Jane Doe)\r\n" +
		"p=+1 617 555-6011\r\n" +
		"c=IN IP4 224.2.17.12/127\r\n" +
		"b=X-YZ:128\r\n" +
		"b=AS:12345\r\n" +
		"t=2873397496 2873404696\r\n" +
		"t=3034423619 3042462419\r\n" +
		"r=604800 3600 0 90000\r\n" +
		"z=2882844526 -3600 2898848070 0\r\n" +
		"k=prompt\r\n" +
		"a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ host\r\n" +
		"a=recvonly\r\n" +
		"m=audio 49170 RTP/AVP 0\r\n" +
		"i=Vivamus a posuere nisl\r\n" +
		"c=IN IP4 203.0.113.1\r\n" +
		"b=X-YZ:128\r\n" +
		"k=prompt\r\n" +
		"a=sendrecv\r\n" +
		"m=video 51372 RTP/AVP 99\r\n" +
		"a=rtpmap:99 h263-1998/90000\r\n"
)

func TestRoundTrip(t *testing.T) {
	for _, test := range []struct {
		Name string
		SDP  string
	}{
		{
			Name: "SessionInformation",
			SDP:  SessionInformationSDP,
		},
		{
			Name: "URI",
			SDP:  URISDP,
		},
		{
			Name: "EmailAddress",
			SDP:  string(EmailAddressSDP),
		},
		{
			Name: "PhoneNumber",
			SDP:  PhoneNumberSDP,
		},
		{
			Name: "SessionConnectionInformation",
			SDP:  SessionConnectionInformationSDP,
		},
		{
			Name: "SessionConnectionInformation",
			SDP:  SessionConnectionInformationSDP,
		},
		{
			Name: "SessionBandwidth",
			SDP:  SessionBandwidthSDP,
		},
		{
			Name: "SessionEncryptionKey",
			SDP:  SessionEncryptionKeySDP,
		},
		{
			Name: "SessionAttributes",
			SDP:  SessionAttributesSDP,
		},
		{
			Name: "MediaName",
			SDP:  MediaNameSDP,
		},
		{
			Name: "MediaTitle",
			SDP:  MediaTitleSDP,
		},
		{
			Name: "MediaConnectionInformation",
			SDP:  MediaConnectionInformationSDP,
		},
		{
			Name: "MediaConnectionInformation",
			SDP:  MediaConnectionInformationSDP,
		},
		{
			Name: "MediaBandwidth",
			SDP:  MediaBandwidthSDP,
		},
		{
			Name: "MediaEncryptionKey",
			SDP:  MediaEncryptionKeySDP,
		},
		{
			Name: "MediaAttributes",
			SDP:  MediaAttributesSDP,
		},
		{
			Name: "CanonicalUnmarshal",
			SDP:  CanonicalUnmarshalSDP,
		},
	} {
		sd := &SessionDescription{}

		err := sd.Unmarshal(test.SDP)
		if got, want := err, error(nil); got != want {
			t.Fatalf("Unmarshal(%s): err=%v, want %v", test.Name, got, want)
		}

		data := sd.Marshal()
		if got, want := data, test.SDP; got != want {
			t.Fatalf("Marshal(%s) = %q, want %q", test.Name, got, want)
		}
	}
}

func TestUnmarshalRepeatTimes(t *testing.T) {
	sd := &SessionDescription{}
	if err := sd.Unmarshal(RepeatTimesSDP); err != nil {
		t.Errorf("error: %v", err)
	}

	actual := sd.Marshal()
	if actual != RepeatTimesSDPExpected {
		t.Errorf("error:\n\nEXPECTED:\n%v\nACTUAL:\n%v", RepeatTimesSDPExpected, actual)
	}
}

func TestUnmarshalTimeZones(t *testing.T) {
	sd := &SessionDescription{}
	if err := sd.Unmarshal(TimeZonesSDP); err != nil {
		t.Errorf("error: %v", err)
	}

	actual := sd.Marshal()
	if actual != TimeZonesSDPExpected {
		t.Errorf("error:\n\nEXPECTED:\n%v\nACTUAL:\n%v", TimeZonesSDPExpected, actual)
	}
}
<|endoftext|>


<commit_before>// Tideland Go Cells - Behaviors - Unit Tests - Finite State Machine
//
// Copyright (C) 2010-2017 Frank Mueller / Tideland / Oldenburg / Germany
//
// All rights reserved. Use of this source code is governed
// by the new BSD license.

package behaviors_test

//--------------------
// IMPORTS
//--------------------

import (
	"context"
	"fmt"
	"testing"
	"time"

	"github.com/tideland/golib/audit"

	"github.com/tideland/gocells/behaviors"
	"github.com/tideland/gocells/cells"
)

//--------------------
// TESTS
//--------------------

// TestFSMBehavior tests the finite state machine behavior.
func TestFSMBehavior(t *testing.T) {
	assert := audit.NewTestingAssertion(t, true)
	ctx := context.Background()
	env := cells.NewEnvironment("fsm-behavior")
	defer env.Stop()

	checkCents := func(id string) int {
		payload, err := env.Request(ctx, id, "cents?", cells.DefaultTimeout)
		assert.Nil(err)
		return payload.GetDefault(0).(int)
	}
	info := func(id string) string {
		payload, err := env.Request(ctx, id, "info?", cells.DefaultTimeout)
		assert.Nil(err)
		return payload.GetDefault("").(string)
	}
	grabCents := func() int {
		payload, err := env.Request(ctx, "restorer", "grab!", cells.DefaultTimeout)
		assert.Nil(err)
		return payload.GetDefault(0).(int)
	}

	lockA := lockMachine{}
	lockB := lockMachine{}

	env.StartCell("lock-a", behaviors.NewFSMBehavior(lockA.Locked))
	env.StartCell("lock-b", behaviors.NewFSMBehavior(lockB.Locked))
	env.StartCell("restorer", newRestorerBehavior())

	env.Subscribe("lock-a", "restorer")
	env.Subscribe("lock-b", "restorer")

	// 1st run: emit not enough and press button.
	env.EmitNew(ctx, "lock-a", "coin!", 20)
	env.EmitNew(ctx, "lock-a", "coin!", 20)
	env.EmitNew(ctx, "lock-a", "coin!", 20)
	env.EmitNew(ctx, "lock-a", "button-press!", nil)

	time.Sleep(100 * time.Millisecond)

	assert.Equal(checkCents("lock-a"), 0)
	assert.Equal(grabCents(), 60)

	// 2nd run: unlock the lock and lock it again.
	env.EmitNew(ctx, "lock-a", "coin!", 50)
	env.EmitNew(ctx, "lock-a", "coin!", 20)
	env.EmitNew(ctx, "lock-a", "coin!", 50)

	time.Sleep(100 * time.Millisecond)

	assert.Equal(info("lock-a"), "state 'unlocked' with 20 cents")

	env.EmitNew(ctx, "lock-a", "button-press!", nil)

	time.Sleep(100 * time.Millisecond)

	assert.Equal(checkCents("lock-a"), 00)
	assert.Equal(info("lock-a"), "state 'locked' with 0 cents")
	assert.Equal(grabCents(), 20)

	// 3rd run: put a screwdriwer in the lock.
	env.EmitNew(ctx, "lock-a", "screwdriver!", nil)

	time.Sleep(100 * time.Millisecond)

	done, err := behaviors.RequestFSMStatus(ctx, env, "lock-a", time.Second)
	assert.Nil(err)
	assert.Equal(done, true)

	// 4th run: try an illegal action.
	env.EmitNew(ctx, "lock-b", "chewing-gum", nil)

	time.Sleep(100 * time.Millisecond)

	done, err = behaviors.RequestFSMStatus(ctx, env, "lock-b", time.Second)
	assert.Equal(done, true)
	assert.ErrorMatch(err, "illegal topic in state 'locked': chewing-gum")
}

//--------------------
// HELPERS
//--------------------

// cents retrieves the cents out of the payload of an event.
func payloadCents(event cells.Event) int {
	return event.Payload().GetInt(cells.PayloadDefault, -1)
}

// lockMachine will be unlocked if enough money is inserted. After
// that it can be locked again.
type lockMachine struct {
	cents int
}

// Locked represents the locked state receiving coins.
func (m *lockMachine) Locked(cell cells.Cell, event cells.Event) (behaviors.FSMState, error) {
	switch event.Topic() {
	case "cents?":
		payload, ok := cells.HasWaiterPayload(event)
		if ok {
			payload.GetWaiter().Set(m.cents)
		}
		return m.Locked, nil
	case "info?":
		info := fmt.Sprintf("state 'locked' with %d cents", m.cents)
		payload, ok := cells.HasWaiterPayload(event)
		if ok {
			payload.GetWaiter().Set(info)
		}
		return m.Locked, nil
	case "coin!":
		cents := payloadCents(event)
		if cents < 1 {
			return nil, fmt.Errorf("do not insert buttons")
		}
		m.cents += cents
		if m.cents > 100 {
			m.cents -= 100
			return m.Unlocked, nil
		}
		return m.Locked, nil
	case "button-press!":
		if m.cents > 0 {
			cell.Environment().EmitNew(event.Context(), "restorer", "drop!", m.cents)
			m.cents = 0
		}
		return m.Locked, nil
	case "screwdriver!":
		// Allow a screwdriver to bring the lock into an undefined state.
		return nil, nil
	}
	return m.Locked, fmt.Errorf("illegal topic in state 'locked': %s", event.Topic())
}

// Unlocked represents the unlocked state receiving coins.
func (m *lockMachine) Unlocked(cell cells.Cell, event cells.Event) (behaviors.FSMState, error) {
	switch event.Topic() {
	case "cents?":
		payload, ok := cells.HasWaiterPayload(event)
		if ok {
			payload.GetWaiter().Set(m.cents)
		}
		return m.Unlocked, nil
	case "info?":
		info := fmt.Sprintf("state 'unlocked' with %d cents", m.cents)
		payload, ok := cells.HasWaiterPayload(event)
		if ok {
			payload.GetWaiter().Set(info)
		}
		return m.Unlocked, nil
	case "coin!":
		cents := payloadCents(event)
		cell.EmitNew(event.Context(), "return", cents)
		return m.Unlocked, nil
	case "button-press!":
		cell.Environment().EmitNew(event.Context(), "restorer", "drop!", m.cents)
		m.cents = 0
		return m.Locked, nil
	}
	return m.Unlocked, fmt.Errorf("illegal topic in state 'unlocked': %s", event.Topic())
}

type restorerBehavior struct {
	cell  cells.Cell
	cents int
}

func newRestorerBehavior() cells.Behavior {
	return &restorerBehavior{nil, 0}
}

func (b *restorerBehavior) Init(c cells.Cell) error {
	b.cell = c
	return nil
}

func (b *restorerBehavior) Terminate() error {
	return nil
}

func (b *restorerBehavior) ProcessEvent(event cells.Event) error {
	switch event.Topic() {
	case "grab!":
		cents := b.cents
		b.cents = 0
		payload, ok := cells.HasWaiterPayload(event)
		if ok {
			payload.GetWaiter().Set(cents)
		}
	case "drop!":
		b.cents += payloadCents(event)
	}
	return nil
}

func (b *restorerBehavior) Recover(err interface{}) error {
	return nil
}

// EOF
<commit_msg>Began refactoring FSM tests<commit_after>// Tideland Go Cells - Behaviors - Unit Tests - Finite State Machine
//
// Copyright (C) 2010-2017 Frank Mueller / Tideland / Oldenburg / Germany
//
// All rights reserved. Use of this source code is governed
// by the new BSD license.

package behaviors_test

//--------------------
// IMPORTS
//--------------------

import (
	"fmt"
	"testing"
	"time"

	"github.com/tideland/golib/audit"

	"github.com/tideland/gocells/behaviors"
	"github.com/tideland/gocells/cells"
)

//--------------------
// TESTS
//--------------------

// TestFSMBehavior tests the finite state machine behavior.
func TestFSMBehavior(t *testing.T) {
	assert := audit.NewTestingAssertion(t, true)
	env := cells.NewEnvironment("fsm-behavior")
	defer env.Stop()

	processor := func(accessor cells.EventSinkAccessor) error {
		return nil
	}

	lockA := lockMachine{}
	lockB := lockMachine{}

	env.StartCell("lock-a", behaviors.NewFSMBehavior(lockA.Locked))
	env.StartCell("lock-b", behaviors.NewFSMBehavior(lockB.Locked))
	env.StartCell("restorer", newRestorerBehavior())
	env.StartCell("collector", behaviors.NewCollectorBehavior(10, processor))

	env.Subscribe("lock-a", "restorer", "collector")
	env.Subscribe("lock-b", "restorer", "collector")

	// 1st run: emit not enough and press button.
	env.EmitNew("lock-a", "coin", 20)
	env.EmitNew("lock-a", "coin", 20)
	env.EmitNew("lock-a", "coin", 20)
	env.EmitNew("lock-a", "button-press", nil)
	env.EmitNew("lock-a", "check-cents", nil)
	env.EmitNew("restorer", "grab", nil)

	// TODO 2017-06-07 Mue Add asserts.

	// 2nd run: unlock the lock and lock it again.
	env.EmitNew("lock-a", "coin", 50)
	env.EmitNew("lock-a", "coin", 20)
	env.EmitNew("lock-a", "coin", 50)
	env.EmitNew("lock-a", "info", nil)
	env.EmitNew("lock-a", "button-press", nil)

	// TODO 2017-06-07 Mue Add asserts.

	// 3rd run: put a screwdriwer in the lock.
	env.EmitNew("lock-a", "screwdriver", nil)

	// TODO 2017-06-07 Mue Add asserts.

	// 4th run: try an illegal action.
	env.EmitNew("lock-b", "chewing-gum", nil)

	// TODO 2017-06-07 Mue Add asserts.
}

//--------------------
// HELPERS
//--------------------

// cents retrieves the cents out of the payload of an event.
func payloadCents(event cells.Event) int {
	return event.Payload().GetInt(cells.PayloadDefault, -1)
}

// lockMachine will be unlocked if enough money is inserted. After
// that it can be locked again.
type lockMachine struct {
	cents int
}

// Locked represents the locked state receiving coins.
func (m *lockMachine) Locked(cell cells.Cell, event cells.Event) (behaviors.FSMState, string, error) {
	switch event.Topic() {
	case "check-cents":
		cell.EmitNew("cents", fmt.Sprintf("check-cents %s: %d", cell.ID(), m.cents))
		return m.Locked, "locked", nil
	case "info?":
		info := fmt.Sprintf("state 'locked' with %d cents", m.cents)
		payload, ok := cells.HasWaiterPayload(event)
		if ok {
			payload.GetWaiter().Set(info)
		}
		return m.Locked, nil
	case "coin!":
		cents := payloadCents(event)
		if cents < 1 {
			return nil, fmt.Errorf("do not insert buttons")
		}
		m.cents += cents
		if m.cents > 100 {
			m.cents -= 100
			return m.Unlocked, nil
		}
		return m.Locked, nil
	case "button-press!":
		if m.cents > 0 {
			cell.Environment().EmitNew(event.Context(), "restorer", "drop!", m.cents)
			m.cents = 0
		}
		return m.Locked, nil
	case "screwdriver!":
		// Allow a screwdriver to bring the lock into an undefined state.
		return nil, nil
	}
	return m.Locked, fmt.Errorf("illegal topic in state 'locked': %s", event.Topic())
}

// Unlocked represents the unlocked state receiving coins.
func (m *lockMachine) Unlocked(cell cells.Cell, event cells.Event) (behaviors.FSMState, error) {
	switch event.Topic() {
	case "cents?":
		payload, ok := cells.HasWaiterPayload(event)
		if ok {
			payload.GetWaiter().Set(m.cents)
		}
		return m.Unlocked, nil
	case "info?":
		info := fmt.Sprintf("state 'unlocked' with %d cents", m.cents)
		payload, ok := cells.HasWaiterPayload(event)
		if ok {
			payload.GetWaiter().Set(info)
		}
		return m.Unlocked, nil
	case "coin!":
		cents := payloadCents(event)
		cell.EmitNew(event.Context(), "return", cents)
		return m.Unlocked, nil
	case "button-press!":
		cell.Environment().EmitNew(event.Context(), "restorer", "drop!", m.cents)
		m.cents = 0
		return m.Locked, nil
	}
	return m.Unlocked, fmt.Errorf("illegal topic in state 'unlocked': %s", event.Topic())
}

type restorerBehavior struct {
	cell  cells.Cell
	cents int
}

func newRestorerBehavior() cells.Behavior {
	return &restorerBehavior{nil, 0}
}

func (b *restorerBehavior) Init(c cells.Cell) error {
	b.cell = c
	return nil
}

func (b *restorerBehavior) Terminate() error {
	return nil
}

func (b *restorerBehavior) ProcessEvent(event cells.Event) error {
	switch event.Topic() {
	case "grab!":
		cents := b.cents
		b.cents = 0
		payload, ok := cells.HasWaiterPayload(event)
		if ok {
			payload.GetWaiter().Set(cents)
		}
	case "drop!":
		b.cents += payloadCents(event)
	}
	return nil
}

func (b *restorerBehavior) Recover(err interface{}) error {
	return nil
}

// EOF
<|endoftext|>


<commit_before>package sourcegraph

import (
	"net/http"
	"net/url"
	"time"

	"golang.org/x/net/context"
	"golang.org/x/oauth2"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"
)

type contextKey int

const (
	grpcEndpointKey contextKey = iota
	httpEndpointKey
	credentialsKey
)

// WithGRPCEndpoint returns a copy of parent whose clients (obtained
// using FromContext) communicate with the given gRPC API endpoint
// URL.
func WithGRPCEndpoint(parent context.Context, url *url.URL) context.Context {
	return context.WithValue(parent, grpcEndpointKey, url)
}

// GRPCEndpoint returns the context's gRPC endpoint URL that was
// previously configured using WithGRPCEndpoint.
func GRPCEndpoint(ctx context.Context) *url.URL {
	url, _ := ctx.Value(grpcEndpointKey).(*url.URL)
	if url == nil {
		panic("no gRPC API endpoint URL set in context")
	}
	return url
}

// WithHTTPEndpoint returns a copy of parent whose clients (obtained
// using FromContext) communicate with the given HTTP API endpoint
// URL.
func WithHTTPEndpoint(parent context.Context, url *url.URL) context.Context {
	return context.WithValue(parent, httpEndpointKey, url)
}

// HTTPEndpoint returns the context's HTTP API endpoint URL that was
// previously configured using WithHTTPEndpoint.
func HTTPEndpoint(ctx context.Context) *url.URL {
	url, _ := ctx.Value(httpEndpointKey).(*url.URL)
	if url == nil {
		panic("no HTTP API endpoint URL set in context")
	}
	return url
}

// Credentials authenticate gRPC and HTTP requests made by an API
// client.
type Credentials interface {
	oauth2.TokenSource
}

// WithCredentials returns a copy of the parent context that uses cred
// as the credentials for future API clients constructed using this
// context (with NewClientFromContext). It replaces (shadows) any
// previously set credentials in the context.
func WithCredentials(parent context.Context, cred Credentials) context.Context {
	return context.WithValue(parent, credentialsKey, cred)
}

// CredentialsFromContext returns the credentials (if any) previously
// set in the context by WithCredentials.
func CredentialsFromContext(ctx context.Context) Credentials {
	cred, ok := ctx.Value(credentialsKey).(Credentials)
	if !ok {
		return nil
	}
	return cred
}

var maxDialTimeout = 3 * time.Second

// NewClientFromContext returns a Sourcegraph API client configured
// using the context (e.g., authenticated using the context's
// credentials).
var NewClientFromContext = func(ctx context.Context) *Client {
	transport := keepAliveTransport

	opts := []grpc.DialOption{
		grpc.WithCodec(GRPCCodec),
	}

	grpcEndpoint := GRPCEndpoint(ctx)
	if grpcEndpoint.Scheme == "https" {
		opts = append(opts, grpc.WithTransportCredentials(credentials.NewClientTLSFromCert(nil, "")))
	}

	cred := CredentialsFromContext(ctx)

	// oauth2.NewClient retrieves the underlying transport from
	// its passed-in context, so we need to create a dummy context
	// using that transport.
	ctxWithTransport := context.WithValue(ctx, oauth2.HTTPClient, &http.Client{Transport: transport})
	transport = oauth2.NewClient(ctxWithTransport, cred).Transport

	// Use contextCredentials instead of directly using the cred
	// so that we can use different credentials for the same
	// connection (in the pool).
	opts = append(opts, grpc.WithPerRPCCredentials(contextCredentials{}))

	// Dial timeout is the lesser of the ctx deadline or
	// maxDialTimeout.
	var timeout time.Duration
	if d, ok := ctx.Deadline(); ok && time.Now().Add(maxDialTimeout).After(d) {
		timeout = d.Sub(time.Now())
	} else {
		timeout = maxDialTimeout
	}
	opts = append(opts, grpc.WithTimeout(timeout))

	conn, err := pooledGRPCDial(grpcEndpoint.Host, opts...)
	if err != nil {
		panic(err)
	}
	c := NewClient(&http.Client{Transport: transport}, conn)
	c.BaseURL = HTTPEndpoint(ctx)
	return c
}

type contextCredentials struct{}

func (contextCredentials) GetRequestMetadata(ctx context.Context) (map[string]string, error) {
	if cred := CredentialsFromContext(ctx); cred != nil {
		s := credentials.TokenSource{TokenSource: cred}
		return s.GetRequestMetadata(ctx)
	}
	return nil, nil
}
<commit_msg>allow passing client metadata<commit_after>package sourcegraph

import (
	"net/http"
	"net/url"
	"time"

	"golang.org/x/net/context"
	"golang.org/x/oauth2"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"
)

type contextKey int

const (
	grpcEndpointKey contextKey = iota
	httpEndpointKey
	credentialsKey
	clientMetadataKey
)

// WithGRPCEndpoint returns a copy of parent whose clients (obtained
// using FromContext) communicate with the given gRPC API endpoint
// URL.
func WithGRPCEndpoint(parent context.Context, url *url.URL) context.Context {
	return context.WithValue(parent, grpcEndpointKey, url)
}

// GRPCEndpoint returns the context's gRPC endpoint URL that was
// previously configured using WithGRPCEndpoint.
func GRPCEndpoint(ctx context.Context) *url.URL {
	url, _ := ctx.Value(grpcEndpointKey).(*url.URL)
	if url == nil {
		panic("no gRPC API endpoint URL set in context")
	}
	return url
}

// WithHTTPEndpoint returns a copy of parent whose clients (obtained
// using FromContext) communicate with the given HTTP API endpoint
// URL.
func WithHTTPEndpoint(parent context.Context, url *url.URL) context.Context {
	return context.WithValue(parent, httpEndpointKey, url)
}

// HTTPEndpoint returns the context's HTTP API endpoint URL that was
// previously configured using WithHTTPEndpoint.
func HTTPEndpoint(ctx context.Context) *url.URL {
	url, _ := ctx.Value(httpEndpointKey).(*url.URL)
	if url == nil {
		panic("no HTTP API endpoint URL set in context")
	}
	return url
}

// Credentials authenticate gRPC and HTTP requests made by an API
// client.
type Credentials interface {
	oauth2.TokenSource
}

// WithCredentials returns a copy of the parent context that uses cred
// as the credentials for future API clients constructed using this
// context (with NewClientFromContext). It replaces (shadows) any
// previously set credentials in the context.
//
// It can be used to add, e.g., trace/span ID metadata for request
// tracing.
func WithCredentials(parent context.Context, cred Credentials) context.Context {
	return context.WithValue(parent, credentialsKey, cred)
}

// CredentialsFromContext returns the credentials (if any) previously
// set in the context by WithCredentials.
func CredentialsFromContext(ctx context.Context) Credentials {
	cred, ok := ctx.Value(credentialsKey).(Credentials)
	if !ok {
		return nil
	}
	return cred
}

// WithClientMetadata returns a copy of the parent context that merges
// in the specified metadata to future API clients constructed using
// this context (with NewClientFromContext). It replaces (shadows) any
// previously set metadata in the context.
func WithClientMetadata(parent context.Context, md map[string]string) context.Context {
	return context.WithValue(parent, clientMetadataKey, md)
}

// clientMetadataFromContext returns the metadata (if any) previously
// set in the context by WithClientMetadata.
func clientMetadataFromContext(ctx context.Context) map[string]string {
	cred, ok := ctx.Value(clientMetadataKey).(map[string]string)
	if !ok {
		return nil
	}
	return cred
}

var maxDialTimeout = 3 * time.Second

// NewClientFromContext returns a Sourcegraph API client configured
// using the context (e.g., authenticated using the context's
// credentials).
var NewClientFromContext = func(ctx context.Context) *Client {
	transport := keepAliveTransport

	opts := []grpc.DialOption{
		grpc.WithCodec(GRPCCodec),
	}

	grpcEndpoint := GRPCEndpoint(ctx)
	if grpcEndpoint.Scheme == "https" {
		opts = append(opts, grpc.WithTransportCredentials(credentials.NewClientTLSFromCert(nil, "")))
	}

	cred := CredentialsFromContext(ctx)

	// oauth2.NewClient retrieves the underlying transport from
	// its passed-in context, so we need to create a dummy context
	// using that transport.
	ctxWithTransport := context.WithValue(ctx, oauth2.HTTPClient, &http.Client{Transport: transport})
	transport = oauth2.NewClient(ctxWithTransport, cred).Transport

	// Use contextCredentials instead of directly using the cred
	// so that we can use different credentials for the same
	// connection (in the pool).
	opts = append(opts, grpc.WithPerRPCCredentials(contextCredentials{}))

	// Dial timeout is the lesser of the ctx deadline or
	// maxDialTimeout.
	var timeout time.Duration
	if d, ok := ctx.Deadline(); ok && time.Now().Add(maxDialTimeout).After(d) {
		timeout = d.Sub(time.Now())
	} else {
		timeout = maxDialTimeout
	}
	opts = append(opts, grpc.WithTimeout(timeout))

	conn, err := pooledGRPCDial(grpcEndpoint.Host, opts...)
	if err != nil {
		panic(err)
	}
	c := NewClient(&http.Client{Transport: transport}, conn)
	c.BaseURL = HTTPEndpoint(ctx)
	return c
}

type contextCredentials struct{}

func (contextCredentials) GetRequestMetadata(ctx context.Context) (map[string]string, error) {
	m := clientMetadataFromContext(ctx)

	if cred := CredentialsFromContext(ctx); cred != nil {
		credMD, err := (credentials.TokenSource{TokenSource: cred}).GetRequestMetadata(ctx)
		if err != nil {
			return nil, err
		}

		if m == nil {
			m = credMD
		} else {
			for k, v := range credMD {
				m[k] = v
			}
		}
	}
	return m, nil
}
<|endoftext|>