<commit_before>package tsdb

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"testing"
	"time"

	"github.com/influxdb/influxdb/influxql"
	"github.com/influxdb/influxdb/meta"
)

var shardID = uint64(1)

func TestWritePointsAndExecuteQuery(t *testing.T) {
	store, executor := testStoreAndExecutor()
	defer os.RemoveAll(store.path)

	pt := NewPoint(
		"cpu",
		map[string]string{"host": "server"},
		map[string]interface{}{"value": 1.0},
		time.Unix(1, 2),
	)

	err := store.WriteToShard(shardID, []Point{pt})
	if err != nil {
		t.Fatalf(err.Error())
	}

	pt.SetTime(time.Unix(2, 3))
	err = store.WriteToShard(shardID, []Point{pt})
	if err != nil {
		t.Fatalf(err.Error())
	}

	got := executeAndGetJSON("select * from cpu", executor)
	exepected := `[{"series":[{"name":"cpu","tags":{"host":"server"},"columns":["time","value"],"values":[["1970-01-01T00:00:01.000000002Z",1],["1970-01-01T00:00:02.000000003Z",1]]}]}]`
	if exepected != got {
		t.Fatalf("exp: %s\ngot: %s", exepected, got)
	}

	store.Close()
	store = NewStore(store.path)
	err = store.Open()
	if err != nil {
		t.Fatalf(err.Error())
	}
	executor.store = store

	got = executeAndGetJSON("select * from cpu", executor)
	if exepected != got {
		t.Fatalf("exp: %s\ngot: %s", exepected, got)
	}
}

func TestDropSeriesStatement(t *testing.T) {
	store, executor := testStoreAndExecutor()
	defer os.RemoveAll(store.path)

	pt := NewPoint(
		"cpu",
		map[string]string{"host": "server"},
		map[string]interface{}{"value": 1.0},
		time.Unix(1, 2),
	)

	err := store.WriteToShard(shardID, []Point{pt})
	if err != nil {
		t.Fatalf(err.Error())
	}

	got := executeAndGetJSON("select * from cpu", executor)
	exepected := `[{"series":[{"name":"cpu","tags":{"host":"server"},"columns":["time","value"],"values":[["1970-01-01T00:00:01.000000002Z",1]]}]}]`
	if exepected != got {
		t.Fatalf("exp: %s\ngot: %s", exepected, got)
	}

	got = executeAndGetJSON("drop series from cpu", executor)

	got = executeAndGetJSON("select * from cpu", executor)
	exepected = `[{}]`
	if exepected != got {
		t.Fatalf("exp: %s\ngot: %s", exepected, got)
	}

	got = executeAndGetJSON("show tag keys from cpu", executor)
	exepected = `[{"series":[{"name":"cpu","columns":["tagKey"]}]}]`
	if exepected != got {
		t.Fatalf("exp: %s\ngot: %s", exepected, got)
	}

	store.Close()
	store = NewStore(store.path)
	store.Open()
	executor.store = store

	got = executeAndGetJSON("select * from cpu", executor)
	exepected = `[{}]`
	if exepected != got {
		t.Fatalf("exp: %s\ngot: %s", exepected, got)
	}

	got = executeAndGetJSON("show tag keys from cpu", executor)
	exepected = `[{"series":[{"name":"cpu","columns":["tagKey"]}]}]`
	if exepected != got {
		t.Fatalf("exp: %s\ngot: %s", exepected, got)
	}
}

func TestDropMeasurementStatement(t *testing.T) {
	store, executor := testStoreAndExecutor()
	defer os.RemoveAll(store.path)

	pt := NewPoint(
		"cpu",
		map[string]string{"host": "server"},
		map[string]interface{}{"value": 1.0},
		time.Unix(1, 2),
	)
	pt2 := NewPoint(
		"memory",
		map[string]string{"host": "server"},
		map[string]interface{}{"value": 1.0},
		time.Unix(1, 2),
	)

	err := store.WriteToShard(shardID, []Point{pt, pt2})
	if err != nil {
		t.Fatalf(err.Error())
	}

	got := executeAndGetJSON("show series", executor)
	exepected := `[{"series":[{"name":"cpu","columns":["_key","host"],"values":[["cpu,host=server","server"]]},{"name":"memory","columns":["_key","host"],"values":[["memory,host=server","server"]]}]}]`
	if exepected != got {
		t.Fatalf("exp: %s\ngot: %s", exepected, got)
	}

	got = executeAndGetJSON("drop measurement memory", executor)
	exepected = `[{}]`
	if exepected != got {
		t.Fatalf("exp: %s\ngot: %s", exepected, got)
	}

	validateDrop := func() {
		got = executeAndGetJSON("show series", executor)
		exepected = `[{"series":[{"name":"cpu","columns":["_key","host"],"values":[["cpu,host=server","server"]]}]}]`
		if exepected != got {
			t.Fatalf("exp: %s\ngot: %s", exepected, got)
		}
		got = executeAndGetJSON("show measurements", executor)
		exepected = `[{"series":[{"name":"measurements","columns":["name"],"values":[["cpu"]]}]}]`
		if exepected != got {
			t.Fatalf("exp: %s\ngot: %s", exepected, got)
		}
		got = executeAndGetJSON("select * from memory", executor)
		exepected = `[{"error":"measurement not found: \"foo\".\"foo\".memory"}]`
		if exepected != got {
			t.Fatalf("exp: %s\ngot: %s", exepected, got)
		}
	}

	validateDrop()
	store.Close()
	store = NewStore(store.path)
	store.Open()
	executor.store = store
	validateDrop()
}

// mock for the metaExecutor
type metaExec struct {
	fn func(stmt influxql.Statement) *influxql.Result
}

func (m *metaExec) ExecuteStatement(stmt influxql.Statement) *influxql.Result {
	return m.fn(stmt)
}

func TestDropDatabase(t *testing.T) {
	store, executor := testStoreAndExecutor()
	defer os.RemoveAll(store.path)

	pt := NewPoint(
		"cpu",
		map[string]string{"host": "server"},
		map[string]interface{}{"value": 1.0},
		time.Unix(1, 2),
	)

	err := store.WriteToShard(shardID, []Point{pt})
	if err != nil {
		t.Fatalf(err.Error())
	}

	got := executeAndGetJSON("select * from cpu", executor)
	expected := `[{"series":[{"name":"cpu","tags":{"host":"server"},"columns":["time","value"],"values":[["1970-01-01T00:00:01.000000002Z",1]]}]}]`
	if expected != got {
		t.Fatalf("exp: %s\ngot: %s", expected, got)
	}

	var name string
	me := &metaExec{fn: func(stmt influxql.Statement) *influxql.Result {
		name = stmt.(*influxql.DropDatabaseStatement).Name
		return &influxql.Result{}
	}}
	executor.MetaStatementExecutor = me

	// verify the database is there on disk
	dbPath := filepath.Join(store.path, "foo")
	if _, err := os.Stat(dbPath); err != nil {
		t.Fatalf("execpted database dir %s to exist", dbPath)
	}

	got = executeAndGetJSON("drop database foo", executor)
	expected = `[{}]`
	if got != expected {
		t.Fatalf("exp: %s\ngot: %s", expected, got)
	}

	if name != "foo" {
		t.Fatalf("exepected the MetaStatementExecutor to be called with database name foo, but got %s", name)
	}

	if _, err := os.Stat(dbPath); !os.IsNotExist(err) {
		t.Fatalf("execpted database dir %s to be gone", dbPath)
	}

	store.Close()
	store = NewStore(store.path)
	store.Open()
	executor.store = store

	err = store.WriteToShard(shardID, []Point{pt})
	if err == nil || err.Error() != "shard not found" {
		t.Fatalf("expected shard to not be found")
	}
}

// ensure that authenticate doesn't return an error if the user count is zero and they're attempting
// to create a user.
func TestAuthenticateIfUserCountZeroAndCreateUser(t *testing.T) {
	store, executor := testStoreAndExecutor()
	defer os.RemoveAll(store.path)
	ms := &testMetastore{userCount: 0}
	executor.MetaStore = ms

	if err := executor.Authorize(nil, mustParseQuery("create user foo with password 'asdf' with all privileges"), ""); err != nil {
		t.Fatalf("should have authenticated if no users and attempting to create a user but got error: %s", err.Error())
	}

	if executor.Authorize(nil, mustParseQuery("create user foo with password 'asdf'"), "") == nil {
		t.Fatalf("should have failed authentication if no user given and no users exist for create user query that doesn't grant all privileges")
	}

	if executor.Authorize(nil, mustParseQuery("select * from foo"), "") == nil {
		t.Fatalf("should have failed authentication if no user given and no users exist for any query other than create user")
	}

	ms.userCount = 1

	if executor.Authorize(nil, mustParseQuery("create user foo with password 'asdf'"), "") == nil {
		t.Fatalf("should have failed authentication if no user given and users exist")
	}

	if executor.Authorize(nil, mustParseQuery("select * from foo"), "") == nil {
		t.Fatalf("should have failed authentication if no user given and users exist")
	}
}

func testStoreAndExecutor() (*Store, *QueryExecutor) {
	path, _ := ioutil.TempDir("", "")

	store := NewStore(path)
	err := store.Open()
	if err != nil {
		panic(err)
	}
	database := "foo"
	retentionPolicy := "bar"
	shardID := uint64(1)
	store.CreateShard(database, retentionPolicy, shardID)

	executor := NewQueryExecutor(store)
	executor.MetaStore = &testMetastore{}

	return store, executor
}

func executeAndGetJSON(query string, executor *QueryExecutor) string {
	ch, err := executor.ExecuteQuery(mustParseQuery(query), "foo", 20)
	if err != nil {
		panic(err.Error())
	}

	var results []*influxql.Result
	for r := range ch {
		results = append(results, r)
	}
	return string(mustMarshalJSON(results))
}

type testMetastore struct {
	userCount int
}

func (t *testMetastore) Database(name string) (*meta.DatabaseInfo, error) {
	return &meta.DatabaseInfo{
		Name: name,
		DefaultRetentionPolicy: "foo",
		RetentionPolicies: []meta.RetentionPolicyInfo{
			{
				Name: "bar",
				ShardGroups: []meta.ShardGroupInfo{
					{
						ID:        uint64(1),
						StartTime: time.Now().Add(-time.Hour),
						EndTime:   time.Now().Add(time.Hour),
						Shards: []meta.ShardInfo{
							{
								ID:       uint64(1),
								OwnerIDs: []uint64{1},
							},
						},
					},
				},
			},
		},
	}, nil
}

func (t *testMetastore) Databases() ([]meta.DatabaseInfo, error) {
	db, _ := t.Database("foo")
	return []meta.DatabaseInfo{*db}, nil
}

func (t *testMetastore) User(name string) (*meta.UserInfo, error) { return nil, nil }

func (t *testMetastore) AdminUserExists() (bool, error) { return false, nil }

func (t *testMetastore) Authenticate(username, password string) (*meta.UserInfo, error) {
	return nil, nil
}

func (t *testMetastore) RetentionPolicy(database, name string) (rpi *meta.RetentionPolicyInfo, err error) {
	return &meta.RetentionPolicyInfo{
		Name: "bar",
		ShardGroups: []meta.ShardGroupInfo{
			{
				ID:        uint64(1),
				StartTime: time.Now().Add(-time.Hour),
				EndTime:   time.Now().Add(time.Hour),
				Shards: []meta.ShardInfo{
					{
						ID:       uint64(1),
						OwnerIDs: []uint64{1},
					},
				},
			},
		},
	}, nil
}

func (t *testMetastore) UserCount() (int, error) {
	return t.userCount, nil
}

// MustParseQuery parses an InfluxQL query. Panic on error.
func mustParseQuery(s string) *influxql.Query {
	q, err := influxql.NewParser(strings.NewReader(s)).ParseQuery()
	if err != nil {
		panic(err.Error())
	}
	return q
}
<commit_msg>Fix spelling in test<commit_after>package tsdb

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"testing"
	"time"

	"github.com/influxdb/influxdb/influxql"
	"github.com/influxdb/influxdb/meta"
)

var shardID = uint64(1)

func TestWritePointsAndExecuteQuery(t *testing.T) {
	store, executor := testStoreAndExecutor()
	defer os.RemoveAll(store.path)

	pt := NewPoint(
		"cpu",
		map[string]string{"host": "server"},
		map[string]interface{}{"value": 1.0},
		time.Unix(1, 2),
	)

	err := store.WriteToShard(shardID, []Point{pt})
	if err != nil {
		t.Fatalf(err.Error())
	}

	pt.SetTime(time.Unix(2, 3))
	err = store.WriteToShard(shardID, []Point{pt})
	if err != nil {
		t.Fatalf(err.Error())
	}

	got := executeAndGetJSON("select * from cpu", executor)
	exepected := `[{"series":[{"name":"cpu","tags":{"host":"server"},"columns":["time","value"],"values":[["1970-01-01T00:00:01.000000002Z",1],["1970-01-01T00:00:02.000000003Z",1]]}]}]`
	if exepected != got {
		t.Fatalf("exp: %s\ngot: %s", exepected, got)
	}

	store.Close()
	store = NewStore(store.path)
	err = store.Open()
	if err != nil {
		t.Fatalf(err.Error())
	}
	executor.store = store

	got = executeAndGetJSON("select * from cpu", executor)
	if exepected != got {
		t.Fatalf("exp: %s\ngot: %s", exepected, got)
	}
}

func TestDropSeriesStatement(t *testing.T) {
	store, executor := testStoreAndExecutor()
	defer os.RemoveAll(store.path)

	pt := NewPoint(
		"cpu",
		map[string]string{"host": "server"},
		map[string]interface{}{"value": 1.0},
		time.Unix(1, 2),
	)

	err := store.WriteToShard(shardID, []Point{pt})
	if err != nil {
		t.Fatalf(err.Error())
	}

	got := executeAndGetJSON("select * from cpu", executor)
	exepected := `[{"series":[{"name":"cpu","tags":{"host":"server"},"columns":["time","value"],"values":[["1970-01-01T00:00:01.000000002Z",1]]}]}]`
	if exepected != got {
		t.Fatalf("exp: %s\ngot: %s", exepected, got)
	}

	got = executeAndGetJSON("drop series from cpu", executor)

	got = executeAndGetJSON("select * from cpu", executor)
	exepected = `[{}]`
	if exepected != got {
		t.Fatalf("exp: %s\ngot: %s", exepected, got)
	}

	got = executeAndGetJSON("show tag keys from cpu", executor)
	exepected = `[{"series":[{"name":"cpu","columns":["tagKey"]}]}]`
	if exepected != got {
		t.Fatalf("exp: %s\ngot: %s", exepected, got)
	}

	store.Close()
	store = NewStore(store.path)
	store.Open()
	executor.store = store

	got = executeAndGetJSON("select * from cpu", executor)
	exepected = `[{}]`
	if exepected != got {
		t.Fatalf("exp: %s\ngot: %s", exepected, got)
	}

	got = executeAndGetJSON("show tag keys from cpu", executor)
	exepected = `[{"series":[{"name":"cpu","columns":["tagKey"]}]}]`
	if exepected != got {
		t.Fatalf("exp: %s\ngot: %s", exepected, got)
	}
}

func TestDropMeasurementStatement(t *testing.T) {
	store, executor := testStoreAndExecutor()
	defer os.RemoveAll(store.path)

	pt := NewPoint(
		"cpu",
		map[string]string{"host": "server"},
		map[string]interface{}{"value": 1.0},
		time.Unix(1, 2),
	)
	pt2 := NewPoint(
		"memory",
		map[string]string{"host": "server"},
		map[string]interface{}{"value": 1.0},
		time.Unix(1, 2),
	)

	err := store.WriteToShard(shardID, []Point{pt, pt2})
	if err != nil {
		t.Fatalf(err.Error())
	}

	got := executeAndGetJSON("show series", executor)
	exepected := `[{"series":[{"name":"cpu","columns":["_key","host"],"values":[["cpu,host=server","server"]]},{"name":"memory","columns":["_key","host"],"values":[["memory,host=server","server"]]}]}]`
	if exepected != got {
		t.Fatalf("exp: %s\ngot: %s", exepected, got)
	}

	got = executeAndGetJSON("drop measurement memory", executor)
	exepected = `[{}]`
	if exepected != got {
		t.Fatalf("exp: %s\ngot: %s", exepected, got)
	}

	validateDrop := func() {
		got = executeAndGetJSON("show series", executor)
		exepected = `[{"series":[{"name":"cpu","columns":["_key","host"],"values":[["cpu,host=server","server"]]}]}]`
		if exepected != got {
			t.Fatalf("exp: %s\ngot: %s", exepected, got)
		}
		got = executeAndGetJSON("show measurements", executor)
		exepected = `[{"series":[{"name":"measurements","columns":["name"],"values":[["cpu"]]}]}]`
		if exepected != got {
			t.Fatalf("exp: %s\ngot: %s", exepected, got)
		}
		got = executeAndGetJSON("select * from memory", executor)
		exepected = `[{"error":"measurement not found: \"foo\".\"foo\".memory"}]`
		if exepected != got {
			t.Fatalf("exp: %s\ngot: %s", exepected, got)
		}
	}

	validateDrop()
	store.Close()
	store = NewStore(store.path)
	store.Open()
	executor.store = store
	validateDrop()
}

// mock for the metaExecutor
type metaExec struct {
	fn func(stmt influxql.Statement) *influxql.Result
}

func (m *metaExec) ExecuteStatement(stmt influxql.Statement) *influxql.Result {
	return m.fn(stmt)
}

func TestDropDatabase(t *testing.T) {
	store, executor := testStoreAndExecutor()
	defer os.RemoveAll(store.path)

	pt := NewPoint(
		"cpu",
		map[string]string{"host": "server"},
		map[string]interface{}{"value": 1.0},
		time.Unix(1, 2),
	)

	err := store.WriteToShard(shardID, []Point{pt})
	if err != nil {
		t.Fatalf(err.Error())
	}

	got := executeAndGetJSON("select * from cpu", executor)
	expected := `[{"series":[{"name":"cpu","tags":{"host":"server"},"columns":["time","value"],"values":[["1970-01-01T00:00:01.000000002Z",1]]}]}]`
	if expected != got {
		t.Fatalf("exp: %s\ngot: %s", expected, got)
	}

	var name string
	me := &metaExec{fn: func(stmt influxql.Statement) *influxql.Result {
		name = stmt.(*influxql.DropDatabaseStatement).Name
		return &influxql.Result{}
	}}
	executor.MetaStatementExecutor = me

	// verify the database is there on disk
	dbPath := filepath.Join(store.path, "foo")
	if _, err := os.Stat(dbPath); err != nil {
		t.Fatalf("execpted database dir %s to exist", dbPath)
	}

	got = executeAndGetJSON("drop database foo", executor)
	expected = `[{}]`
	if got != expected {
		t.Fatalf("exp: %s\ngot: %s", expected, got)
	}

	if name != "foo" {
		t.Fatalf("expected the MetaStatementExecutor to be called with database name foo, but got %s", name)
	}

	if _, err := os.Stat(dbPath); !os.IsNotExist(err) {
		t.Fatalf("expected database dir %s to be gone", dbPath)
	}

	store.Close()
	store = NewStore(store.path)
	store.Open()
	executor.store = store

	err = store.WriteToShard(shardID, []Point{pt})
	if err == nil || err.Error() != "shard not found" {
		t.Fatalf("expected shard to not be found")
	}
}

// ensure that authenticate doesn't return an error if the user count is zero and they're attempting
// to create a user.
func TestAuthenticateIfUserCountZeroAndCreateUser(t *testing.T) {
	store, executor := testStoreAndExecutor()
	defer os.RemoveAll(store.path)
	ms := &testMetastore{userCount: 0}
	executor.MetaStore = ms

	if err := executor.Authorize(nil, mustParseQuery("create user foo with password 'asdf' with all privileges"), ""); err != nil {
		t.Fatalf("should have authenticated if no users and attempting to create a user but got error: %s", err.Error())
	}

	if executor.Authorize(nil, mustParseQuery("create user foo with password 'asdf'"), "") == nil {
		t.Fatalf("should have failed authentication if no user given and no users exist for create user query that doesn't grant all privileges")
	}

	if executor.Authorize(nil, mustParseQuery("select * from foo"), "") == nil {
		t.Fatalf("should have failed authentication if no user given and no users exist for any query other than create user")
	}

	ms.userCount = 1

	if executor.Authorize(nil, mustParseQuery("create user foo with password 'asdf'"), "") == nil {
		t.Fatalf("should have failed authentication if no user given and users exist")
	}

	if executor.Authorize(nil, mustParseQuery("select * from foo"), "") == nil {
		t.Fatalf("should have failed authentication if no user given and users exist")
	}
}

func testStoreAndExecutor() (*Store, *QueryExecutor) {
	path, _ := ioutil.TempDir("", "")

	store := NewStore(path)
	err := store.Open()
	if err != nil {
		panic(err)
	}
	database := "foo"
	retentionPolicy := "bar"
	shardID := uint64(1)
	store.CreateShard(database, retentionPolicy, shardID)

	executor := NewQueryExecutor(store)
	executor.MetaStore = &testMetastore{}

	return store, executor
}

func executeAndGetJSON(query string, executor *QueryExecutor) string {
	ch, err := executor.ExecuteQuery(mustParseQuery(query), "foo", 20)
	if err != nil {
		panic(err.Error())
	}

	var results []*influxql.Result
	for r := range ch {
		results = append(results, r)
	}
	return string(mustMarshalJSON(results))
}

type testMetastore struct {
	userCount int
}

func (t *testMetastore) Database(name string) (*meta.DatabaseInfo, error) {
	return &meta.DatabaseInfo{
		Name: name,
		DefaultRetentionPolicy: "foo",
		RetentionPolicies: []meta.RetentionPolicyInfo{
			{
				Name: "bar",
				ShardGroups: []meta.ShardGroupInfo{
					{
						ID:        uint64(1),
						StartTime: time.Now().Add(-time.Hour),
						EndTime:   time.Now().Add(time.Hour),
						Shards: []meta.ShardInfo{
							{
								ID:       uint64(1),
								OwnerIDs: []uint64{1},
							},
						},
					},
				},
			},
		},
	}, nil
}

func (t *testMetastore) Databases() ([]meta.DatabaseInfo, error) {
	db, _ := t.Database("foo")
	return []meta.DatabaseInfo{*db}, nil
}

func (t *testMetastore) User(name string) (*meta.UserInfo, error) { return nil, nil }

func (t *testMetastore) AdminUserExists() (bool, error) { return false, nil }

func (t *testMetastore) Authenticate(username, password string) (*meta.UserInfo, error) {
	return nil, nil
}

func (t *testMetastore) RetentionPolicy(database, name string) (rpi *meta.RetentionPolicyInfo, err error) {
	return &meta.RetentionPolicyInfo{
		Name: "bar",
		ShardGroups: []meta.ShardGroupInfo{
			{
				ID:        uint64(1),
				StartTime: time.Now().Add(-time.Hour),
				EndTime:   time.Now().Add(time.Hour),
				Shards: []meta.ShardInfo{
					{
						ID:       uint64(1),
						OwnerIDs: []uint64{1},
					},
				},
			},
		},
	}, nil
}

func (t *testMetastore) UserCount() (int, error) {
	return t.userCount, nil
}

// MustParseQuery parses an InfluxQL query. Panic on error.
func mustParseQuery(s string) *influxql.Query {
	q, err := influxql.NewParser(strings.NewReader(s)).ParseQuery()
	if err != nil {
		panic(err.Error())
	}
	return q
}
<|endoftext|>


<commit_before>// Copyright 2015 Hajime Hoshi
//
// 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.

// +build !js,!windows

package driver

import (
	"fmt"
	"io"
	"runtime"

	"github.com/hajimehoshi/go-openal/openal"
)

// As x/mobile/exp/audio/al is broken on Mac OS X (https://github.com/golang/go/issues/15075),
// let's use timshannon/go-openal.

const (
	maxBufferNum = 8
)

type Player struct {
	alDevice   *openal.Device
	alSource   openal.Source
	alBuffers  []openal.Buffer
	source     io.Reader
	sampleRate int
	isClosed   bool
	alFormat   openal.Format
}

func alFormat(channelNum, bytesPerSample int) openal.Format {
	switch {
	case channelNum == 1 && bytesPerSample == 1:
		return openal.FormatMono8
	case channelNum == 1 && bytesPerSample == 2:
		return openal.FormatMono16
	case channelNum == 2 && bytesPerSample == 1:
		return openal.FormatStereo8
	case channelNum == 2 && bytesPerSample == 2:
		return openal.FormatStereo16
	}
	panic(fmt.Sprintf("driver: invalid channel num (%d) or bytes per sample (%d)", channelNum, bytesPerSample))
}

func NewPlayer(src io.Reader, sampleRate, channelNum, bytesPerSample int) (*Player, error) {
	d := openal.OpenDevice("")
	if d == nil {
		return nil, fmt.Errorf("driver: OpenDevice must not return nil")
	}
	c := d.CreateContext()
	if c == nil {
		return nil, fmt.Errorf("driver: CreateContext must not return nil")
	}
	// Don't check openal.Err until making the current context is done.
	// Linux might fail this check even though it succeeds (#204).
	c.Activate()
	if err := openal.Err(); err != nil {
		return nil, fmt.Errorf("driver: Activate: %v", err)
	}
	s := openal.NewSource()
	if err := openal.Err(); err != nil {
		return nil, fmt.Errorf("driver: NewSource: %v", err)
	}
	p := &Player{
		alDevice:   d,
		alSource:   s,
		alBuffers:  []openal.Buffer{},
		source:     src,
		sampleRate: sampleRate,
		alFormat:   alFormat(channelNum, bytesPerSample),
	}
	runtime.SetFinalizer(p, (*Player).Close)

	bs := openal.NewBuffers(maxBufferNum)
	emptyBytes := make([]byte, bufferSize)
	for _, b := range bs {
		// Note that the third argument of only the first buffer is used.
		b.SetData(p.alFormat, emptyBytes, int32(p.sampleRate))
		p.alSource.QueueBuffer(b)
	}
	p.alSource.Play()
	return p, nil
}

const (
	bufferSize = 1024
)

var (
	tmpBuffer    = make([]byte, bufferSize)
	tmpAlBuffers = make([]openal.Buffer, maxBufferNum)
)

func (p *Player) Proceed() error {
	if err := openal.Err(); err != nil {
		return fmt.Errorf("driver: starting Proceed: %v", err)
	}
	processedNum := p.alSource.BuffersProcessed()
	if 0 < processedNum {
		bufs := tmpAlBuffers[:processedNum]
		p.alSource.UnqueueBuffers(bufs)
		if err := openal.Err(); err != nil {
			return fmt.Errorf("driver: UnqueueBuffers: %v", err)
		}
		p.alBuffers = append(p.alBuffers, bufs...)
	}

	if 0 < len(p.alBuffers) {
		n, err := p.source.Read(tmpBuffer)
		if 0 < n {
			buf := p.alBuffers[0]
			p.alBuffers = p.alBuffers[1:]
			buf.SetData(p.alFormat, tmpBuffer[:n], int32(p.sampleRate))
			p.alSource.QueueBuffer(buf)
			if err := openal.Err(); err != nil {
				return fmt.Errorf("driver: QueueBuffer: %v", err)
			}
		}
		if err != nil {
			return err
		}
	}

	if p.alSource.State() == openal.Stopped || p.alSource.State() == openal.Initial {
		p.alSource.Rewind()
		p.alSource.Play()
		if err := openal.Err(); err != nil {
			return fmt.Errorf("driver: Rwind or Play: %v", err)
		}
	}

	return nil
}

func (p *Player) Close() error {
	if err := openal.Err(); err != nil {
		return fmt.Errorf("driver: starting Close: %v", err)
	}
	if p.isClosed {
		return nil
	}
	var bs []openal.Buffer
	p.alSource.Rewind()
	p.alSource.Play()
	if n := p.alSource.BuffersQueued(); 0 < n {
		bs = make([]openal.Buffer, n)
		p.alSource.UnqueueBuffers(bs)
		p.alBuffers = append(p.alBuffers, bs...)
	}
	p.alDevice.CloseDevice()
	p.isClosed = true
	if err := openal.Err(); err != nil {
		return fmt.Errorf("driver: CloseDevice: %v", err)
	}
	runtime.SetFinalizer(p, nil)
	return nil
}
<commit_msg>audio: Fix wrong comments<commit_after>// Copyright 2015 Hajime Hoshi
//
// 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.

// +build !js,!windows

package driver

import (
	"fmt"
	"io"
	"runtime"

	"github.com/hajimehoshi/go-openal/openal"
)

// As x/mobile/exp/audio/al is broken on Mac OS X (https://github.com/golang/go/issues/15075),
// let's use github.com/hajimehoshi/go-openal instead.

const (
	maxBufferNum = 8
)

type Player struct {
	alDevice   *openal.Device
	alSource   openal.Source
	alBuffers  []openal.Buffer
	source     io.Reader
	sampleRate int
	isClosed   bool
	alFormat   openal.Format
}

func alFormat(channelNum, bytesPerSample int) openal.Format {
	switch {
	case channelNum == 1 && bytesPerSample == 1:
		return openal.FormatMono8
	case channelNum == 1 && bytesPerSample == 2:
		return openal.FormatMono16
	case channelNum == 2 && bytesPerSample == 1:
		return openal.FormatStereo8
	case channelNum == 2 && bytesPerSample == 2:
		return openal.FormatStereo16
	}
	panic(fmt.Sprintf("driver: invalid channel num (%d) or bytes per sample (%d)", channelNum, bytesPerSample))
}

func NewPlayer(src io.Reader, sampleRate, channelNum, bytesPerSample int) (*Player, error) {
	d := openal.OpenDevice("")
	if d == nil {
		return nil, fmt.Errorf("driver: OpenDevice must not return nil")
	}
	c := d.CreateContext()
	if c == nil {
		return nil, fmt.Errorf("driver: CreateContext must not return nil")
	}
	// Don't check openal.Err until making the current context is done.
	// Linux might fail this check even though it succeeds (#204).
	c.Activate()
	if err := openal.Err(); err != nil {
		return nil, fmt.Errorf("driver: Activate: %v", err)
	}
	s := openal.NewSource()
	if err := openal.Err(); err != nil {
		return nil, fmt.Errorf("driver: NewSource: %v", err)
	}
	p := &Player{
		alDevice:   d,
		alSource:   s,
		alBuffers:  []openal.Buffer{},
		source:     src,
		sampleRate: sampleRate,
		alFormat:   alFormat(channelNum, bytesPerSample),
	}
	runtime.SetFinalizer(p, (*Player).Close)

	bs := openal.NewBuffers(maxBufferNum)
	emptyBytes := make([]byte, bufferSize)
	for _, b := range bs {
		// Note that the third argument of only the first buffer is used.
		b.SetData(p.alFormat, emptyBytes, int32(p.sampleRate))
		p.alSource.QueueBuffer(b)
	}
	p.alSource.Play()
	return p, nil
}

const (
	bufferSize = 1024
)

var (
	tmpBuffer    = make([]byte, bufferSize)
	tmpAlBuffers = make([]openal.Buffer, maxBufferNum)
)

func (p *Player) Proceed() error {
	if err := openal.Err(); err != nil {
		return fmt.Errorf("driver: starting Proceed: %v", err)
	}
	processedNum := p.alSource.BuffersProcessed()
	if 0 < processedNum {
		bufs := tmpAlBuffers[:processedNum]
		p.alSource.UnqueueBuffers(bufs)
		if err := openal.Err(); err != nil {
			return fmt.Errorf("driver: UnqueueBuffers: %v", err)
		}
		p.alBuffers = append(p.alBuffers, bufs...)
	}

	if 0 < len(p.alBuffers) {
		n, err := p.source.Read(tmpBuffer)
		if 0 < n {
			buf := p.alBuffers[0]
			p.alBuffers = p.alBuffers[1:]
			buf.SetData(p.alFormat, tmpBuffer[:n], int32(p.sampleRate))
			p.alSource.QueueBuffer(buf)
			if err := openal.Err(); err != nil {
				return fmt.Errorf("driver: QueueBuffer: %v", err)
			}
		}
		if err != nil {
			return err
		}
	}

	if p.alSource.State() == openal.Stopped || p.alSource.State() == openal.Initial {
		p.alSource.Rewind()
		p.alSource.Play()
		if err := openal.Err(); err != nil {
			return fmt.Errorf("driver: Rwind or Play: %v", err)
		}
	}

	return nil
}

func (p *Player) Close() error {
	if err := openal.Err(); err != nil {
		return fmt.Errorf("driver: starting Close: %v", err)
	}
	if p.isClosed {
		return nil
	}
	var bs []openal.Buffer
	p.alSource.Rewind()
	p.alSource.Play()
	if n := p.alSource.BuffersQueued(); 0 < n {
		bs = make([]openal.Buffer, n)
		p.alSource.UnqueueBuffers(bs)
		p.alBuffers = append(p.alBuffers, bs...)
	}
	p.alDevice.CloseDevice()
	p.isClosed = true
	if err := openal.Err(); err != nil {
		return fmt.Errorf("driver: CloseDevice: %v", err)
	}
	runtime.SetFinalizer(p, nil)
	return nil
}
<|endoftext|>


<commit_before>// Package xhr provides GopherJS bindings for the XMLHttpRequest API.
//
// This package provides two ways of using XHR. The first one is via
// the Request type and the NewRequest function. This way, one can
// specify all desired details of the request's behaviour (timeout,
// response format). It also allows access to response details such as
// the status code. Furthermore, using this way is required if one
// wants to abort in-flight requests or if one wants to register
// additional event listeners.
//
//   r := xhr.NewRequest("GET", "/endpoint")
//   r.SetTimeout(time.Second)
//   r.ResponseType = "document"
//   err := r.Send(nil)
//   if err != nil { handle_error() }
//   // r.Response will contain a JavaScript Document element that can
//   // for example be used with the js/dom package.
//
//
// The other way is via the package function Send, which is a helper
// that internally constructs a Request and assigns sane defaults to
// it. It's the easiest way of doing an XHR request that should just
// return unprocessed data.
//
//     data, err := xhr.Send("GET", "/endpoint", nil)
//     if err != nil { handle_error() }
//     console.Log("Retrieved data", data)
//
package xhr

import (
	"errors"

	"github.com/gopherjs/gopherjs/js"
	"honnef.co/go/js/util"
)

// The possible values of Request.ReadyState.
const (
	// Open has not been called yet
	Unsent = iota
	// Send has not been called yet
	Opened
	HeadersReceived
	Loading
	Done
)

// Request wraps XMLHttpRequest objects. New instances have to be
// created with NewRequest. Each instance may only be used for a
// single request.
type Request struct {
	js.Object
	util.EventTarget
	ReadyState      int       `js:"readyState"`
	Response        js.Object `js:"response"`
	ResponseText    string    `js:"responseText"`
	ResponseType    string    `js:"responseType"`
	ResponseXML     js.Object `js:"responseXML"`
	Status          int       `js:"status"`
	StatusText      string    `js:"statusText"`
	Timeout         int       `js:"timeout"`
	WithCredentials bool      `js:"withCredentials"`

	ch chan error
}

// Upload wraps XMLHttpRequestUpload objects.
type Upload struct {
	js.Object
	util.EventTarget
}

// Upload returns the XMLHttpRequestUpload object associated with the
// request. It can be used to register events for tracking the
// progress of uploads.
func (r *Request) Upload() *Upload {
	o := r.Get("upload")
	return &Upload{o, util.EventTarget{Object: o}}
}

// ErrAborted is the error returned by Send when a request was
// aborted.
var ErrAborted = errors.New("request aborted")

// ErrTimeout is the error returned by Send when a request timed out.
var ErrTimeout = errors.New("request timed out")

// NewRequest creates a new XMLHttpRequest object, which may be used
// for a single request.
func NewRequest(method, url string) *Request {
	o := js.Global.Get("XMLHttpRequest").New()
	r := &Request{Object: o, EventTarget: util.EventTarget{Object: o}}
	r.Call("open", method, url, true)
	return r
}

// ResponseHeaders returns all response headers.
func (r *Request) ResponseHeaders() string {
	return r.Call("getAllResponseHeaders").Str()
}

// ResponseHeader returns the value of the specified header.
func (r *Request) ResponseHeader(name string) string {
	value := r.Call("getResponseHeader", name)
	if value.IsNull() {
		return ""
	}
	return value.Str()
}

// Abort will abort the request. The corresponding Send will return
// ErrAborted, unless the request has already succeeded.
func (r *Request) Abort() {
	if r.ch == nil {
		return
	}

	r.Call("abort")
	select {
	case r.ch <- ErrAborted:
	default:
	}
}

// OverrideMimeType overrides the MIME type returned by the server.
func (r *Request) OverrideMimeType(mimetype string) {
	r.Call("overrideMimeType", mimetype)
}

// Send sends the request that was prepared with Open. The data
// argument is optional and can either be a string payload, or a
// js.Object containing an ArrayBufferView, Blob, Document or
// Formdata.
//
// Send will block until a response was received or an error occured.
//
// Only errors of the network layer are treated as errors. HTTP status
// codes 4xx and 5xx are not treated as errors. In order to check
// status codes, use the Request's Status field.
func (r *Request) Send(data interface{}) error {
	if r.ch != nil {
		panic("must not use a Request for multiple requests")
	}
	r.ch = make(chan error, 1)
	r.AddEventListener("load", false, func(js.Object) {
		go func() { r.ch <- nil }()
	})
	r.AddEventListener("error", false, func(o js.Object) {
		go func() { r.ch <- &js.Error{Object: o} }()
	})
	r.AddEventListener("timeout", false, func(js.Object) {
		go func() { r.ch <- ErrTimeout }()
	})
	r.Call("send", data)
	val := <-r.ch
	return val
}

// SetRequestHeader sets a header of the request.
func (r *Request) SetRequestHeader(header, value string) {
	r.Call("setRequestHeader", header, value)
}

// Send constructs a new Request and sends it. The response
// corresponds to the request's ResponseText field, or the empty
// string in case of an error.
//
// Only errors of the network layer are treated as errors. HTTP status
// codes 4xx and 5xx are not treated as errors. In order to check
// status codes, use NewRequest instead.
func Send(method, url string, data interface{}) (string, error) {
	xhr := NewRequest(method, url)
	err := xhr.Send(data)
	if err != nil {
		return "", err
	}
	return xhr.ResponseText, nil
}
<commit_msg>add constants for valid response types<commit_after>// Package xhr provides GopherJS bindings for the XMLHttpRequest API.
//
// This package provides two ways of using XHR. The first one is via
// the Request type and the NewRequest function. This way, one can
// specify all desired details of the request's behaviour (timeout,
// response format). It also allows access to response details such as
// the status code. Furthermore, using this way is required if one
// wants to abort in-flight requests or if one wants to register
// additional event listeners.
//
//   r := xhr.NewRequest("GET", "/endpoint")
//   r.SetTimeout(time.Second)
//   r.ResponseType = "document"
//   err := r.Send(nil)
//   if err != nil { handle_error() }
//   // r.Response will contain a JavaScript Document element that can
//   // for example be used with the js/dom package.
//
//
// The other way is via the package function Send, which is a helper
// that internally constructs a Request and assigns sane defaults to
// it. It's the easiest way of doing an XHR request that should just
// return unprocessed data.
//
//     data, err := xhr.Send("GET", "/endpoint", nil)
//     if err != nil { handle_error() }
//     console.Log("Retrieved data", data)
//
package xhr

import (
	"errors"

	"github.com/gopherjs/gopherjs/js"
	"honnef.co/go/js/util"
)

// The possible values of Request.ReadyState.
const (
	// Open has not been called yet
	Unsent = iota
	// Send has not been called yet
	Opened
	HeadersReceived
	Loading
	Done
)

// The possible values of Request.ResponseType
const (
	ArrayBuffer = "arraybuffer"
	Blob        = "blob"
	Document    = "document"
	JSON        = "json"
	Text        = "text"
)

// Request wraps XMLHttpRequest objects. New instances have to be
// created with NewRequest. Each instance may only be used for a
// single request.
type Request struct {
	js.Object
	util.EventTarget
	ReadyState      int       `js:"readyState"`
	Response        js.Object `js:"response"`
	ResponseText    string    `js:"responseText"`
	ResponseType    string    `js:"responseType"`
	ResponseXML     js.Object `js:"responseXML"`
	Status          int       `js:"status"`
	StatusText      string    `js:"statusText"`
	Timeout         int       `js:"timeout"`
	WithCredentials bool      `js:"withCredentials"`

	ch chan error
}

// Upload wraps XMLHttpRequestUpload objects.
type Upload struct {
	js.Object
	util.EventTarget
}

// Upload returns the XMLHttpRequestUpload object associated with the
// request. It can be used to register events for tracking the
// progress of uploads.
func (r *Request) Upload() *Upload {
	o := r.Get("upload")
	return &Upload{o, util.EventTarget{Object: o}}
}

// ErrAborted is the error returned by Send when a request was
// aborted.
var ErrAborted = errors.New("request aborted")

// ErrTimeout is the error returned by Send when a request timed out.
var ErrTimeout = errors.New("request timed out")

// NewRequest creates a new XMLHttpRequest object, which may be used
// for a single request.
func NewRequest(method, url string) *Request {
	o := js.Global.Get("XMLHttpRequest").New()
	r := &Request{Object: o, EventTarget: util.EventTarget{Object: o}}
	r.Call("open", method, url, true)
	return r
}

// ResponseHeaders returns all response headers.
func (r *Request) ResponseHeaders() string {
	return r.Call("getAllResponseHeaders").Str()
}

// ResponseHeader returns the value of the specified header.
func (r *Request) ResponseHeader(name string) string {
	value := r.Call("getResponseHeader", name)
	if value.IsNull() {
		return ""
	}
	return value.Str()
}

// Abort will abort the request. The corresponding Send will return
// ErrAborted, unless the request has already succeeded.
func (r *Request) Abort() {
	if r.ch == nil {
		return
	}

	r.Call("abort")
	select {
	case r.ch <- ErrAborted:
	default:
	}
}

// OverrideMimeType overrides the MIME type returned by the server.
func (r *Request) OverrideMimeType(mimetype string) {
	r.Call("overrideMimeType", mimetype)
}

// Send sends the request that was prepared with Open. The data
// argument is optional and can either be a string payload, or a
// js.Object containing an ArrayBufferView, Blob, Document or
// Formdata.
//
// Send will block until a response was received or an error occured.
//
// Only errors of the network layer are treated as errors. HTTP status
// codes 4xx and 5xx are not treated as errors. In order to check
// status codes, use the Request's Status field.
func (r *Request) Send(data interface{}) error {
	if r.ch != nil {
		panic("must not use a Request for multiple requests")
	}
	r.ch = make(chan error, 1)
	r.AddEventListener("load", false, func(js.Object) {
		go func() { r.ch <- nil }()
	})
	r.AddEventListener("error", false, func(o js.Object) {
		go func() { r.ch <- &js.Error{Object: o} }()
	})
	r.AddEventListener("timeout", false, func(js.Object) {
		go func() { r.ch <- ErrTimeout }()
	})
	r.Call("send", data)
	val := <-r.ch
	return val
}

// SetRequestHeader sets a header of the request.
func (r *Request) SetRequestHeader(header, value string) {
	r.Call("setRequestHeader", header, value)
}

// Send constructs a new Request and sends it. The response
// corresponds to the request's ResponseText field, or the empty
// string in case of an error.
//
// Only errors of the network layer are treated as errors. HTTP status
// codes 4xx and 5xx are not treated as errors. In order to check
// status codes, use NewRequest instead.
func Send(method, url string, data interface{}) (string, error) {
	xhr := NewRequest(method, url)
	err := xhr.Send(data)
	if err != nil {
		return "", err
	}
	return xhr.ResponseText, nil
}
<|endoftext|>


<commit_before>// Yam (Yet Another Mux)

package main

import (
	"fmt"
	"net/http"
	"strings"
)

type handler func(http.ResponseWriter, *http.Request)

type Yam struct {
	Root *Route
}

func NewYam() *Yam {
	return &Yam{
		Root: &Route{},
	}
}

func route(path string, router *Route) *Route {
	parts := strings.Split(path, "/")[1:]
	routes := router.Routes

	fmt.Println("Start Router:", router.path)
	fmt.Println("Stat Path:", path)
	fullPath := router.path + path

	for i, part := range parts {
		fmt.Println("Part:", part)
		if i == len(parts)-1 {

			for _, route := range routes {
				if route.leaf == part {
					fmt.Println("Route Exists")
					fmt.Println("--------------")
					return route
				}
			}

			route := &Route{leaf: part, path: fullPath}
			fmt.Println("Add:", route.path)
			fmt.Println("Router:", router.path)
			router.Routes = append(router.Routes, route)

			fmt.Println("--------------")

			return route

		} else {
			for _, route := range routes {
				if route.leaf == part {
					fmt.Println("Leaf:", route.leaf)
					router = route
				} else {
					fmt.Println("Router:", router.path)
					route := &Route{leaf: part, path: router.path + path}
					router.Routes = append(router.Routes, route)
					router = route
				}
			}

		}
	}

	return nil
}

func (y *Yam) Route(path string) *Route {
	return route(path, y.Root)
}

func (y *Yam) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	parts := strings.Split(r.URL.Path, "/")[1:]
	fmt.Println(parts)

	routes := y.Root.Routes
	for i, part := range parts {
		fmt.Println(part)
		for _, route := range routes {
			fmt.Println("Leaf:", route.leaf)
			if route.leaf == part {
				fmt.Println("Leaf ==", part)
				if i < len(parts)-1 {
					routes = route.Routes
					break
				} else {
					fmt.Println("Found: ", route.path)

					var handler http.Handler
					switch r.Method {
					case "GET":
						handler = route.GetHandler
					}

					if handler != nil {
						handler.ServeHTTP(w, r)
						return
					}

					fmt.Println("No handler for method")
					w.WriteHeader(http.StatusMethodNotAllowed)
					return

				}
			}
		}
	}

	// If we get here then we have not found a route
	fmt.Println("Not Found")
	w.WriteHeader(http.StatusNotFound)
}

type Route struct {
	leaf   string   // a part of a URL path, /foo/bar - a leaf would be foo and bar
	path   string   // full url path
	Routes []*Route // Routes that live under this route

	GetHandler http.Handler
}

func (r *Route) Route(path string) *Route {
	return route(path, r)
}

func (r *Route) Get(h handler) *Route {
	r.GetHandler = http.HandlerFunc(h)

	return r
}

func GetRootHandler(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("Get Root Handler"))
}

func GetFooHandler(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("Get Foo Handler"))
}

func GetAHandler(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("Get A Handler"))
}

func GetBHandler(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("Get B Handler"))
}

func GetCHandler(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("Get C Handler"))
}

func GetDHandler(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("Get D Handler"))
}

func main() {
	y := NewYam()

	y.Route("/").Get(GetRootHandler)
	y.Route("/foo")

	a := y.Route("/a").Get(GetAHandler)
	a.Route("/b").Get(GetBHandler)
	c := a.Route("/c").Get(GetCHandler)
	c.Route("/d").Get(GetDHandler)
	c.Route("/d/e").Get(func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("E Handler"))
	})

	fmt.Printf("%+v\n", y)

	http.ListenAndServe(":5000", y)
}
<commit_msg>More HTTP Verbs<commit_after>// Yam (Yet Another Mux)

package main

import (
	"fmt"
	"net/http"
	"strings"
)

type handler func(http.ResponseWriter, *http.Request)

type Yam struct {
	Root *Route
}

func NewYam() *Yam {
	return &Yam{
		Root: &Route{},
	}
}

func route(path string, router *Route) *Route {
	parts := strings.Split(path, "/")[1:]
	routes := router.Routes

	fmt.Println("Start Router:", router.path)
	fmt.Println("Stat Path:", path)
	fullPath := router.path + path

	for i, part := range parts {
		fmt.Println("Part:", part)
		if i == len(parts)-1 {

			for _, route := range routes {
				if route.leaf == part {
					fmt.Println("Route Exists")
					fmt.Println("--------------")
					return route
				}
			}

			route := &Route{leaf: part, path: fullPath}
			fmt.Println("Add:", route.path)
			fmt.Println("Router:", router.path)
			router.Routes = append(router.Routes, route)

			fmt.Println("--------------")

			return route

		} else {
			for _, route := range routes {
				if route.leaf == part {
					fmt.Println("Leaf:", route.leaf)
					router = route
				} else {
					fmt.Println("Router:", router.path)
					route := &Route{leaf: part, path: router.path + path}
					router.Routes = append(router.Routes, route)
					router = route
				}
			}

		}
	}

	return nil
}

func (y *Yam) Route(path string) *Route {
	return route(path, y.Root)
}

func (y *Yam) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	parts := strings.Split(r.URL.Path, "/")[1:]
	fmt.Println(parts)

	routes := y.Root.Routes
	for i, part := range parts {
		fmt.Println(part)
		for _, route := range routes {
			fmt.Println("Leaf:", route.leaf)
			if route.leaf == part {
				fmt.Println("Leaf ==", part)
				if i < len(parts)-1 {
					routes = route.Routes
					break
				} else {
					fmt.Println("Found: ", route.path)

					var handler http.Handler
					switch r.Method {
					case "GET":
						handler = route.getHandler
					case "POST":
						handler = route.postHandler
					case "PUT":
						handler = route.putHandler
					case "PATCH":
						handler = route.patchHandler
					case "DELETE":
						handler = route.deleteHandler
					}

					if handler != nil {
						handler.ServeHTTP(w, r)
						return
					}

					fmt.Println("No handler for method")
					w.WriteHeader(http.StatusMethodNotAllowed)
					return

				}
			}
		}
	}

	// If we get here then we have not found a route
	fmt.Println("Not Found")
	w.WriteHeader(http.StatusNotFound)
}

type Route struct {
	leaf   string   // a part of a URL path, /foo/bar - a leaf would be foo and bar
	path   string   // full url path
	Routes []*Route // Routes that live under this route

	getHandler    http.Handler
	postHandler   http.Handler
	putHandler    http.Handler
	patchHandler  http.Handler
	deleteHandler http.Handler
}

func (r *Route) Route(path string) *Route {
	return route(path, r)
}

func (r *Route) Get(h handler) *Route {
	r.getHandler = http.HandlerFunc(h)

	return r
}

func (r *Route) Post(h handler) *Route {
	r.postHandler = http.HandlerFunc(h)

	return r
}

func (r *Route) Put(h handler) *Route {
	r.putHandler = http.HandlerFunc(h)

	return r
}

func (r *Route) Delete(h handler) *Route {
	r.deleteHandler = http.HandlerFunc(h)

	return r
}

func (r *Route) Patch(h handler) *Route {
	r.patchHandler = http.HandlerFunc(h)

	return r
}

func GetRootHandler(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("Get Root Handler"))
}

func GetFooHandler(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("Get Foo Handler"))
}

func GetAHandler(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("Get A Handler"))
}

func GetBHandler(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("Get B Handler"))
}

func GetCHandler(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("Get C Handler"))
}

func GetDHandler(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("Get D Handler"))
}

func main() {
	y := NewYam()

	y.Route("/").Get(GetRootHandler)
	y.Route("/get").Get(func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("GET"))
	})
	y.Route("/post").Post(func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("POST"))
	})
	y.Route("/put").Put(func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("PUT"))
	})
	y.Route("/patch").Patch(func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("PATCH"))
	})
	y.Route("/delete").Delete(func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("DELETE"))
	})

	a := y.Route("/a").Get(GetAHandler)
	a.Route("/b").Get(GetBHandler)
	a.Route("/b").Put(func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("PUT B Handler"))
	})
	c := a.Route("/b/c").Get(GetCHandler)
	c.Route("/d").Get(GetDHandler)
	e := c.Route("/d/e").Get(func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("E Handler"))
	})
	e.Route("/f").Get(func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("F Handler"))
	})

	fmt.Printf("%+v\n", y)

	http.ListenAndServe(":5000", y)
}
<|endoftext|>


<commit_before>// Code generated by mockery v1.0.0. DO NOT EDIT.

package ca

import (
	x509 "crypto/x509"

	mock "github.com/stretchr/testify/mock"
)

// MockProvider is an autogenerated mock type for the Provider type
type MockProvider struct {
	mock.Mock
}

// ActiveIntermediate provides a mock function with given fields:
func (_m *MockProvider) ActiveIntermediate() (string, error) {
	ret := _m.Called()

	var r0 string
	if rf, ok := ret.Get(0).(func() string); ok {
		r0 = rf()
	} else {
		r0 = ret.Get(0).(string)
	}

	var r1 error
	if rf, ok := ret.Get(1).(func() error); ok {
		r1 = rf()
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}

// ActiveRoot provides a mock function with given fields:
func (_m *MockProvider) ActiveRoot() (string, error) {
	ret := _m.Called()

	var r0 string
	if rf, ok := ret.Get(0).(func() string); ok {
		r0 = rf()
	} else {
		r0 = ret.Get(0).(string)
	}

	var r1 error
	if rf, ok := ret.Get(1).(func() error); ok {
		r1 = rf()
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}

// Cleanup provides a mock function with given fields: providerTypeChange, config
func (_m *MockProvider) Cleanup(providerTypeChange bool, config map[string]interface{}) error {
	ret := _m.Called(providerTypeChange, config)

	var r0 error
	if rf, ok := ret.Get(0).(func(bool, map[string]interface{}) error); ok {
		r0 = rf(providerTypeChange, config)
	} else {
		r0 = ret.Error(0)
	}

	return r0
}

// Configure provides a mock function with given fields: cfg
func (_m *MockProvider) Configure(cfg ProviderConfig) error {
	ret := _m.Called(cfg)

	var r0 error
	if rf, ok := ret.Get(0).(func(ProviderConfig) error); ok {
		r0 = rf(cfg)
	} else {
		r0 = ret.Error(0)
	}

	return r0
}

// CrossSignCA provides a mock function with given fields: _a0
func (_m *MockProvider) CrossSignCA(_a0 *x509.Certificate) (string, error) {
	ret := _m.Called(_a0)

	var r0 string
	if rf, ok := ret.Get(0).(func(*x509.Certificate) string); ok {
		r0 = rf(_a0)
	} else {
		r0 = ret.Get(0).(string)
	}

	var r1 error
	if rf, ok := ret.Get(1).(func(*x509.Certificate) error); ok {
		r1 = rf(_a0)
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}

// GenerateIntermediate provides a mock function with given fields:
func (_m *MockProvider) GenerateIntermediate() (string, error) {
	ret := _m.Called()

	var r0 string
	if rf, ok := ret.Get(0).(func() string); ok {
		r0 = rf()
	} else {
		r0 = ret.Get(0).(string)
	}

	var r1 error
	if rf, ok := ret.Get(1).(func() error); ok {
		r1 = rf()
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}

// GenerateIntermediateCSR provides a mock function with given fields:
func (_m *MockProvider) GenerateIntermediateCSR() (string, error) {
	ret := _m.Called()

	var r0 string
	if rf, ok := ret.Get(0).(func() string); ok {
		r0 = rf()
	} else {
		r0 = ret.Get(0).(string)
	}

	var r1 error
	if rf, ok := ret.Get(1).(func() error); ok {
		r1 = rf()
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}

// GenerateRoot provides a mock function with given fields:
func (_m *MockProvider) GenerateRoot() error {
	ret := _m.Called()

	var r0 error
	if rf, ok := ret.Get(0).(func() error); ok {
		r0 = rf()
	} else {
		r0 = ret.Error(0)
	}

	return r0
}

// SetIntermediate provides a mock function with given fields: intermediatePEM, rootPEM
func (_m *MockProvider) SetIntermediate(intermediatePEM string, rootPEM string) error {
	ret := _m.Called(intermediatePEM, rootPEM)

	var r0 error
	if rf, ok := ret.Get(0).(func(string, string) error); ok {
		r0 = rf(intermediatePEM, rootPEM)
	} else {
		r0 = ret.Error(0)
	}

	return r0
}

// Sign provides a mock function with given fields: _a0
func (_m *MockProvider) Sign(_a0 *x509.CertificateRequest) (string, error) {
	ret := _m.Called(_a0)

	var r0 string
	if rf, ok := ret.Get(0).(func(*x509.CertificateRequest) string); ok {
		r0 = rf(_a0)
	} else {
		r0 = ret.Get(0).(string)
	}

	var r1 error
	if rf, ok := ret.Get(1).(func(*x509.CertificateRequest) error); ok {
		r1 = rf(_a0)
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}

// SignIntermediate provides a mock function with given fields: _a0
func (_m *MockProvider) SignIntermediate(_a0 *x509.CertificateRequest) (string, error) {
	ret := _m.Called(_a0)

	var r0 string
	if rf, ok := ret.Get(0).(func(*x509.CertificateRequest) string); ok {
		r0 = rf(_a0)
	} else {
		r0 = ret.Get(0).(string)
	}

	var r1 error
	if rf, ok := ret.Get(1).(func(*x509.CertificateRequest) error); ok {
		r1 = rf(_a0)
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}

// State provides a mock function with given fields:
func (_m *MockProvider) State() (map[string]string, error) {
	ret := _m.Called()

	var r0 map[string]string
	if rf, ok := ret.Get(0).(func() map[string]string); ok {
		r0 = rf()
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).(map[string]string)
		}
	}

	var r1 error
	if rf, ok := ret.Get(1).(func() error); ok {
		r1 = rf()
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}

// SupportsCrossSigning provides a mock function with given fields:
func (_m *MockProvider) SupportsCrossSigning() (bool, error) {
	ret := _m.Called()

	var r0 bool
	if rf, ok := ret.Get(0).(func() bool); ok {
		r0 = rf()
	} else {
		r0 = ret.Get(0).(bool)
	}

	var r1 error
	if rf, ok := ret.Get(1).(func() error); ok {
		r1 = rf()
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}
<commit_msg>ca: update MockProvider for new interface<commit_after>// Code generated by mockery v1.0.0. DO NOT EDIT.

package ca

import (
	x509 "crypto/x509"

	mock "github.com/stretchr/testify/mock"
)

// MockProvider is an autogenerated mock type for the Provider type
type MockProvider struct {
	mock.Mock
}

// ActiveIntermediate provides a mock function with given fields:
func (_m *MockProvider) ActiveIntermediate() (string, error) {
	ret := _m.Called()

	var r0 string
	if rf, ok := ret.Get(0).(func() string); ok {
		r0 = rf()
	} else {
		r0 = ret.Get(0).(string)
	}

	var r1 error
	if rf, ok := ret.Get(1).(func() error); ok {
		r1 = rf()
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}

// Cleanup provides a mock function with given fields: providerTypeChange, otherConfig
func (_m *MockProvider) Cleanup(providerTypeChange bool, otherConfig map[string]interface{}) error {
	ret := _m.Called(providerTypeChange, otherConfig)

	var r0 error
	if rf, ok := ret.Get(0).(func(bool, map[string]interface{}) error); ok {
		r0 = rf(providerTypeChange, otherConfig)
	} else {
		r0 = ret.Error(0)
	}

	return r0
}

// Configure provides a mock function with given fields: cfg
func (_m *MockProvider) Configure(cfg ProviderConfig) error {
	ret := _m.Called(cfg)

	var r0 error
	if rf, ok := ret.Get(0).(func(ProviderConfig) error); ok {
		r0 = rf(cfg)
	} else {
		r0 = ret.Error(0)
	}

	return r0
}

// CrossSignCA provides a mock function with given fields: _a0
func (_m *MockProvider) CrossSignCA(_a0 *x509.Certificate) (string, error) {
	ret := _m.Called(_a0)

	var r0 string
	if rf, ok := ret.Get(0).(func(*x509.Certificate) string); ok {
		r0 = rf(_a0)
	} else {
		r0 = ret.Get(0).(string)
	}

	var r1 error
	if rf, ok := ret.Get(1).(func(*x509.Certificate) error); ok {
		r1 = rf(_a0)
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}

// GenerateIntermediate provides a mock function with given fields:
func (_m *MockProvider) GenerateIntermediate() (string, error) {
	ret := _m.Called()

	var r0 string
	if rf, ok := ret.Get(0).(func() string); ok {
		r0 = rf()
	} else {
		r0 = ret.Get(0).(string)
	}

	var r1 error
	if rf, ok := ret.Get(1).(func() error); ok {
		r1 = rf()
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}

// GenerateIntermediateCSR provides a mock function with given fields:
func (_m *MockProvider) GenerateIntermediateCSR() (string, error) {
	ret := _m.Called()

	var r0 string
	if rf, ok := ret.Get(0).(func() string); ok {
		r0 = rf()
	} else {
		r0 = ret.Get(0).(string)
	}

	var r1 error
	if rf, ok := ret.Get(1).(func() error); ok {
		r1 = rf()
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}

// GenerateRoot provides a mock function with given fields:
func (_m *MockProvider) GenerateRoot() (RootResult, error) {
	ret := _m.Called()

	var r0 RootResult
	if rf, ok := ret.Get(0).(func() RootResult); ok {
		r0 = rf()
	} else {
		r0 = ret.Get(0).(RootResult)
	}

	var r1 error
	if rf, ok := ret.Get(1).(func() error); ok {
		r1 = rf()
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}

// SetIntermediate provides a mock function with given fields: intermediatePEM, rootPEM
func (_m *MockProvider) SetIntermediate(intermediatePEM string, rootPEM string) error {
	ret := _m.Called(intermediatePEM, rootPEM)

	var r0 error
	if rf, ok := ret.Get(0).(func(string, string) error); ok {
		r0 = rf(intermediatePEM, rootPEM)
	} else {
		r0 = ret.Error(0)
	}

	return r0
}

// Sign provides a mock function with given fields: _a0
func (_m *MockProvider) Sign(_a0 *x509.CertificateRequest) (string, error) {
	ret := _m.Called(_a0)

	var r0 string
	if rf, ok := ret.Get(0).(func(*x509.CertificateRequest) string); ok {
		r0 = rf(_a0)
	} else {
		r0 = ret.Get(0).(string)
	}

	var r1 error
	if rf, ok := ret.Get(1).(func(*x509.CertificateRequest) error); ok {
		r1 = rf(_a0)
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}

// SignIntermediate provides a mock function with given fields: _a0
func (_m *MockProvider) SignIntermediate(_a0 *x509.CertificateRequest) (string, error) {
	ret := _m.Called(_a0)

	var r0 string
	if rf, ok := ret.Get(0).(func(*x509.CertificateRequest) string); ok {
		r0 = rf(_a0)
	} else {
		r0 = ret.Get(0).(string)
	}

	var r1 error
	if rf, ok := ret.Get(1).(func(*x509.CertificateRequest) error); ok {
		r1 = rf(_a0)
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}

// State provides a mock function with given fields:
func (_m *MockProvider) State() (map[string]string, error) {
	ret := _m.Called()

	var r0 map[string]string
	if rf, ok := ret.Get(0).(func() map[string]string); ok {
		r0 = rf()
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).(map[string]string)
		}
	}

	var r1 error
	if rf, ok := ret.Get(1).(func() error); ok {
		r1 = rf()
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}

// SupportsCrossSigning provides a mock function with given fields:
func (_m *MockProvider) SupportsCrossSigning() (bool, error) {
	ret := _m.Called()

	var r0 bool
	if rf, ok := ret.Get(0).(func() bool); ok {
		r0 = rf()
	} else {
		r0 = ret.Get(0).(bool)
	}

	var r1 error
	if rf, ok := ret.Get(1).(func() error); ok {
		r1 = rf()
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}
<|endoftext|>


<commit_before>package score

import (
	"encoding/json"
	"fmt"
	"io"
	"runtime"
	"strings"
)

// GolbalSecret represents the unique course identifier that will be used in
// the Score constructors. Users of this package must set this variable
// appropriately (for example in func init) before using any exported
// function in this package. The value of the global secret is available from
// the teachers panel after a course has been created.
var GlobalSecret = "NOT SET"

// Score encodes the score of a test or a group of tests. When a test passes in
// Autograder, a JSON object representing this struct is emitted to the output
// stream.
//
// The JSON object emitted on the output stream contains a Secret hash value
// which is a unique course identifier that can be obtained from the teachers
// panel in Autograder. This Secret is used by Autograder to extract Score
// objects from the output stream. All other output is ignored when computing
// the score.
//
// The Autograder computes the score accoring to the formula below, providing
// a percentage score for a test or a group of tests. The Weight parameter can
// be used to give more/less value to some Score objects (representing
// different test sets). For example, a Weight of 2 on test A and a Weight of 1
// on all other tests will give twice the score for test A compare to the
// other tests.
//
// If you want to only give a score for completing a test, then you can simply
// use NewScoreMax(1, 1), without using any API methods to decrement the score,
// giving a result of Score = MaxScore = 1 (and Weight = 1).
//
// The Autograder computes the final score as follows:
// TotalWeight     = sum(Weight)
// TaskScore[i]    = Score[i] / MaxScore[i], gives {0 < TaskScore < 1}
// TaskWeight[i]   = Weight[i] / TotalWeight
// Score           = sum(TaskScore[i]*TaskWeight[i]), gives {0 < Score < 1}
type Score struct {
	Secret   string // the unique identifier for the course
	TestName string // name of the test
	Score    int    // the score obtained
	MaxScore int    // max score possible to get on this specific test
	Weight   int    // the weight of this test; used to compute final grade
}

// NewScore returns a new Score object with the given max and weight.
// The Score.Score field is 0 initially, and so Score.Inc() and IncBy() can
// be called on the returned Score object.
// Note that the TestName is initialized to the name of the calling method.
func NewScore(max, weight int) *Score {
	return &Score{
		Secret:   GlobalSecret,
		TestName: testName(),
		MaxScore: max,
		Weight:   weight,
	}
}

// NewScoreMax returns a new Score object with the given max and weight.
// The Score.Score field is max initially, and so Score.Dec() and DecBy() can
// be called on the returned Score object.
// Note that the TestName is initialized to the name of the calling method.
func NewScoreMax(max, weight int) *Score {
	return &Score{
		Secret:   GlobalSecret,
		TestName: testName(),
		Score:    max,
		MaxScore: max,
		Weight:   weight,
	}
}

// IncBy increments score n times or until score equals MaxScore.
func (s *Score) IncBy(n int) {
	if s.Score+n < s.MaxScore {
		s.Score += n
	} else {
		s.Score = s.MaxScore
	}
}

// Inc increments score if score is less than MaxScore.
func (s *Score) Inc() {
	if s.Score < s.MaxScore {
		s.Score++
	}
}

// Dec decrements score if score is greater than zero.
func (s *Score) Dec() {
	if s.Score > 0 {
		s.Score--
	}
}

// DecBy decrements score n times or until Score equals zero.
func (s *Score) DecBy(n int) {
	if s.Score-n > 0 {
		s.Score -= n
	} else {
		s.Score = 0
	}
}

// String returns a string representation of score s.
// Format: "TestName: 2/10 cases passed".
func (s *Score) String() string {
	return fmt.Sprintf("%s: %d/%d cases passed", s.TestName, s.Score, s.MaxScore)
}

// WriteString writes the string representation of s to w.
func (s *Score) WriteString(w io.Writer) {
	fmt.Fprintf(w, "%v\n", s)
}

// WriteJSON writes the JSON representation of s to w.
func (s *Score) WriteJSON(w io.Writer) {
	b, err := json.Marshal(s)
	if err != nil {
		fmt.Fprintf(w, "json.Marshal error: \n%v\n", err)
	}
	fmt.Fprintf(w, "\n%s\n", b)
}

// testName returns the name of a test when used by the Score-constructors.
//
// NOTE: This function is specifically constructed to be called from the
// Score-constructors. It is not safe for other usage due to the hard-coded
// skip constant used when calling runtime.Callers.
func testName() string {
	const skip = 3
	pc := make([]uintptr, skip)
	runtime.Callers(skip, pc)
	f := runtime.FuncForPC(pc[0])
	s := strings.Split(f.Name(), ".")
	if s == nil {
		return "Unknown test"
	}
	return s[len(s)-1]
}
<commit_msg>catch panicing function and reset score before printing<commit_after>package score

import (
	"encoding/json"
	"fmt"
	"io"
	"runtime"
	"strings"
)

// GolbalSecret represents the unique course identifier that will be used in
// the Score constructors. Users of this package must set this variable
// appropriately (for example in func init) before using any exported
// function in this package. The value of the global secret is available from
// the teachers panel after a course has been created.
var GlobalSecret = "NOT SET"

// Score encodes the score of a test or a group of tests. When a test passes in
// Autograder, a JSON object representing this struct is emitted to the output
// stream.
//
// The JSON object emitted on the output stream contains a Secret hash value
// which is a unique course identifier that can be obtained from the teachers
// panel in Autograder. This Secret is used by Autograder to extract Score
// objects from the output stream. All other output is ignored when computing
// the score.
//
// The Autograder computes the score accoring to the formula below, providing
// a percentage score for a test or a group of tests. The Weight parameter can
// be used to give more/less value to some Score objects (representing
// different test sets). For example, a Weight of 2 on test A and a Weight of 1
// on all other tests will give twice the score for test A compare to the
// other tests.
//
// If you want to only give a score for completing a test, then you can simply
// use NewScoreMax(1, 1), without using any API methods to decrement the score,
// giving a result of Score = MaxScore = 1 (and Weight = 1).
//
// The Autograder computes the final score as follows:
// TotalWeight     = sum(Weight)
// TaskScore[i]    = Score[i] / MaxScore[i], gives {0 < TaskScore < 1}
// TaskWeight[i]   = Weight[i] / TotalWeight
// Score           = sum(TaskScore[i]*TaskWeight[i]), gives {0 < Score < 1}
type Score struct {
	Secret   string // the unique identifier for the course
	TestName string // name of the test
	Score    int    // the score obtained
	MaxScore int    // max score possible to get on this specific test
	Weight   int    // the weight of this test; used to compute final grade
}

// NewScore returns a new Score object with the given max and weight.
// The Score.Score field is 0 initially, and so Score.Inc() and IncBy() can
// be called on the returned Score object.
// Note that the TestName is initialized to the name of the calling method.
func NewScore(max, weight int) *Score {
	return &Score{
		Secret:   GlobalSecret,
		TestName: testName(),
		MaxScore: max,
		Weight:   weight,
	}
}

// NewScoreMax returns a new Score object with the given max and weight.
// The Score.Score field is max initially, and so Score.Dec() and DecBy() can
// be called on the returned Score object.
// Note that the TestName is initialized to the name of the calling method.
func NewScoreMax(max, weight int) *Score {
	return &Score{
		Secret:   GlobalSecret,
		TestName: testName(),
		Score:    max,
		MaxScore: max,
		Weight:   weight,
	}
}

// IncBy increments score n times or until score equals MaxScore.
func (s *Score) IncBy(n int) {
	if s.Score+n < s.MaxScore {
		s.Score += n
	} else {
		s.Score = s.MaxScore
	}
}

// Inc increments score if score is less than MaxScore.
func (s *Score) Inc() {
	if s.Score < s.MaxScore {
		s.Score++
	}
}

// Dec decrements score if score is greater than zero.
func (s *Score) Dec() {
	if s.Score > 0 {
		s.Score--
	}
}

// DecBy decrements score n times or until Score equals zero.
func (s *Score) DecBy(n int) {
	if s.Score-n > 0 {
		s.Score -= n
	} else {
		s.Score = 0
	}
}

// String returns a string representation of score s.
// Format: "TestName: 2/10 cases passed".
func (s *Score) String() string {
	return fmt.Sprintf("%s: %d/%d cases passed", s.TestName, s.Score, s.MaxScore)
}

// WriteString writes the string representation of s to w.
func (s *Score) WriteString(w io.Writer) {
	// check if calling func paniced before calling this
	if r := recover(); r != nil {
		// reset score for paniced functions
		sc.Score = 0
	}
	fmt.Fprintf(w, "%v\n", s)
}

// WriteJSON writes the JSON representation of s to w.
func (s *Score) WriteJSON(w io.Writer) {
	// check if calling func paniced before calling this
	if r := recover(); r != nil {
		// reset score for paniced functions
		sc.Score = 0
	}
	b, err := json.Marshal(s)
	if err != nil {
		fmt.Fprintf(w, "json.Marshal error: \n%v\n", err)
	}
	fmt.Fprintf(w, "\n%s\n", b)
}

// testName returns the name of a test when used by the Score-constructors.
//
// NOTE: This function is specifically constructed to be called from the
// Score-constructors. It is not safe for other usage due to the hard-coded
// skip constant used when calling runtime.Callers.
func testName() string {
	const skip = 3
	pc := make([]uintptr, skip)
	runtime.Callers(skip, pc)
	f := runtime.FuncForPC(pc[0])
	s := strings.Split(f.Name(), ".")
	if s == nil {
		return "Unknown test"
	}
	return s[len(s)-1]
}
<|endoftext|>


<commit_before>package terraform

import (
	"log"
	"strings"

	"github.com/hashicorp/terraform/config/module"
	"github.com/hashicorp/terraform/dag"
)

type RemovedModuleTransformer struct {
	Module *module.Tree // root module
	State  *State
}

func (t *RemovedModuleTransformer) Transform(g *Graph) error {
	// nothing to remove if there's no state!
	if t.State == nil {
		return nil
	}

	// get a map of all nodes by path, so we can connect anything that might be
	// in the module
	refMap := map[string][]dag.Vertex{}
	for _, v := range g.Vertices() {
		if pn, ok := v.(GraphNodeSubPath); ok {
			path := normalizeModulePath(pn.Path())[1:]
			p := modulePrefixStr(path)
			refMap[p] = append(refMap[p], v)
		}
	}

	for _, m := range t.State.Modules {
		c := t.Module.Child(m.Path[1:])
		if c != nil {
			continue
		}

		log.Printf("[DEBUG] module %s no longer in config\n", modulePrefixStr(m.Path))

		node := &NodeModuleRemoved{PathValue: m.Path}
		g.Add(node)

		// connect this to anything that contains the module's path
		refPath := modulePrefixStr(m.Path)
		for p, nodes := range refMap {
			if strings.HasPrefix(p, refPath) {
				for _, parent := range nodes {
					g.Connect(dag.BasicEdge(node, parent))
				}
			}
		}
	}
	return nil
}
<commit_msg>only add nodes in RemovedModuleTransformer<commit_after>package terraform

import (
	"log"

	"github.com/hashicorp/terraform/config/module"
)

// RemoveModuleTransformer implements GraphTransformer to add nodes indicating
// when a module was removed from the configuration.
type RemovedModuleTransformer struct {
	Module *module.Tree // root module
	State  *State
}

func (t *RemovedModuleTransformer) Transform(g *Graph) error {
	// nothing to remove if there's no state!
	if t.State == nil {
		return nil
	}

	for _, m := range t.State.Modules {
		c := t.Module.Child(m.Path[1:])
		if c != nil {
			continue
		}

		log.Printf("[DEBUG] module %s no longer in config\n", modulePrefixStr(m.Path))
		g.Add(&NodeModuleRemoved{PathValue: m.Path})
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2018 The Terraformer 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 providerwrapper //nolint

import (
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"runtime"
	"strings"

	"github.com/GoogleCloudPlatform/terraformer/terraformutils/terraformerstring"

	"github.com/zclconf/go-cty/cty"

	"github.com/hashicorp/go-hclog"
	"github.com/hashicorp/go-plugin"
	"github.com/hashicorp/terraform/configs/configschema"
	tfplugin "github.com/hashicorp/terraform/plugin"
	"github.com/hashicorp/terraform/providers"
	"github.com/hashicorp/terraform/terraform"
	"github.com/hashicorp/terraform/version"
)

// DefaultDataDir is the default directory for storing local data.
const DefaultDataDir = ".terraform"

// DefaultPluginVendorDir is the location in the config directory to look for
// user-added plugin binaries. Terraform only reads from this path if it
// exists, it is never created by terraform.
const DefaultPluginVendorDir = "terraform.d/plugins/" + pluginMachineName

// pluginMachineName is the directory name used in new plugin paths.
const pluginMachineName = runtime.GOOS + "_" + runtime.GOARCH

type ProviderWrapper struct {
	Provider     *tfplugin.GRPCProvider
	client       *plugin.Client
	rpcClient    plugin.ClientProtocol
	providerName string
	config       cty.Value
	schema       *providers.GetSchemaResponse
}

func NewProviderWrapper(providerName string, providerConfig cty.Value, verbose bool) (*ProviderWrapper, error) {
	p := &ProviderWrapper{}
	p.providerName = providerName
	p.config = providerConfig
	err := p.initProvider(verbose)

	return p, err
}

func (p *ProviderWrapper) Kill() {
	p.client.Kill()
}

func (p *ProviderWrapper) GetSchema() *providers.GetSchemaResponse {
	if p.schema == nil {
		r := p.Provider.GetSchema()
		p.schema = &r
	}
	return p.schema
}

func (p *ProviderWrapper) GetReadOnlyAttributes(resourceTypes []string) (map[string][]string, error) {
	r := p.GetSchema()

	if r.Diagnostics.HasErrors() {
		return nil, r.Diagnostics.Err()
	}
	readOnlyAttributes := map[string][]string{}
	for resourceName, obj := range r.ResourceTypes {
		if terraformerstring.ContainsString(resourceTypes, resourceName) {
			readOnlyAttributes[resourceName] = append(readOnlyAttributes[resourceName], "^id$")
			for k, v := range obj.Block.Attributes {
				if !v.Optional && !v.Required {
					if v.Type.IsListType() || v.Type.IsSetType() {
						readOnlyAttributes[resourceName] = append(readOnlyAttributes[resourceName], "^"+k+".(.*)")
					} else {
						readOnlyAttributes[resourceName] = append(readOnlyAttributes[resourceName], "^"+k+"$")
					}
				}
			}
			readOnlyAttributes[resourceName] = p.readObjBlocks(obj.Block.BlockTypes, readOnlyAttributes[resourceName], "-1")
		}
	}
	return readOnlyAttributes, nil
}

func (p *ProviderWrapper) readObjBlocks(block map[string]*configschema.NestedBlock, readOnlyAttributes []string, parent string) []string {
	for k, v := range block {
		if len(v.BlockTypes) > 0 {
			readOnlyAttributes = p.readObjBlocks(v.BlockTypes, readOnlyAttributes, k)
		}
		fieldCount := 0
		for key, l := range v.Attributes {
			if !l.Optional && !l.Required {
				fieldCount++
				switch v.Nesting {
				case configschema.NestingList:
					if parent == "-1" {
						readOnlyAttributes = append(readOnlyAttributes, "^"+k+".[0-9]."+key+"($|\\.[0-9]|\\.#)")
					} else {
						readOnlyAttributes = append(readOnlyAttributes, "^"+parent+".(.*)."+key+"$")
					}
				case configschema.NestingSet:
					if parent == "-1" {
						readOnlyAttributes = append(readOnlyAttributes, "^"+k+".[0-9]."+key+"$")
					} else {
						readOnlyAttributes = append(readOnlyAttributes, "^"+parent+".(.*)."+key+"($|\\.(.*))")
					}
				case configschema.NestingMap:
					readOnlyAttributes = append(readOnlyAttributes, parent+"."+key)
				default:
					readOnlyAttributes = append(readOnlyAttributes, parent+"."+key+"$")
				}
			}
		}
		if fieldCount == len(v.Block.Attributes) && fieldCount > 0 {
			readOnlyAttributes = append(readOnlyAttributes, "^"+k)
		}
	}
	return readOnlyAttributes
}

func (p *ProviderWrapper) Refresh(info *terraform.InstanceInfo, state *terraform.InstanceState) (*terraform.InstanceState, error) {
	schema := p.GetSchema()
	impliedType := schema.ResourceTypes[info.Type].Block.ImpliedType()
	priorState, err := state.AttrsAsObjectValue(impliedType)
	if err != nil {
		return nil, err
	}
	resp := p.Provider.ReadResource(providers.ReadResourceRequest{
		TypeName:   info.Type,
		PriorState: priorState,
		Private:    []byte{},
	})

	if resp.Diagnostics.HasErrors() {
		// retry with regular import command - without resource attributes
		importResponse := p.Provider.ImportResourceState(providers.ImportResourceStateRequest{
			TypeName: info.Type,
			ID:       state.ID,
		})
		if importResponse.Diagnostics.HasErrors() {
			return nil, resp.Diagnostics.Err()
		}
		if len(importResponse.ImportedResources) == 0 {
			return nil, errors.New("not able to import resource for a given ID")
		}
		return terraform.NewInstanceStateShimmedFromValue(importResponse.ImportedResources[0].State, int(schema.ResourceTypes[info.Type].Version)), nil
	}

	if resp.NewState.IsNull() {
		msg := fmt.Sprintf("ERROR: Read resource response is null for resource %s", info.Id)
		return nil, errors.New(msg)
	}

	return terraform.NewInstanceStateShimmedFromValue(resp.NewState, int(schema.ResourceTypes[info.Type].Version)), nil
}

func (p *ProviderWrapper) initProvider(verbose bool) error {
	providerFilePath, err := getProviderFileName(p.providerName)
	if err != nil {
		return err
	}
	options := hclog.LoggerOptions{
		Name:   "plugin",
		Level:  hclog.Error,
		Output: os.Stdout,
	}
	if verbose {
		options.Level = hclog.Trace
	}
	logger := hclog.New(&options)
	p.client = plugin.NewClient(
		&plugin.ClientConfig{
			Cmd:              exec.Command(providerFilePath),
			HandshakeConfig:  tfplugin.Handshake,
			VersionedPlugins: tfplugin.VersionedPlugins,
			Managed:          true,
			Logger:           logger,
			AllowedProtocols: []plugin.Protocol{plugin.ProtocolGRPC},
			AutoMTLS:         true,
		})
	p.rpcClient, err = p.client.Client()
	if err != nil {
		return err
	}
	raw, err := p.rpcClient.Dispense(tfplugin.ProviderPluginName)
	if err != nil {
		return err
	}

	p.Provider = raw.(*tfplugin.GRPCProvider)

	config, err := p.GetSchema().Provider.Block.CoerceValue(p.config)
	if err != nil {
		return err
	}
	p.Provider.Configure(providers.ConfigureRequest{
		TerraformVersion: version.Version,
		Config:           config,
	})

	return nil
}

func getProviderFileName(providerName string) (string, error) {
	defaultDataDir := os.Getenv("TF_DATA_DIR")
	if defaultDataDir == "" {
		defaultDataDir = DefaultDataDir
	}
	pluginPath := defaultDataDir + string(os.PathSeparator) + "plugins" + string(os.PathSeparator) + runtime.GOOS + "_" + runtime.GOARCH
	files, err := ioutil.ReadDir(pluginPath)
	if err != nil {
		pluginPath = os.Getenv("HOME") + string(os.PathSeparator) + "." + DefaultPluginVendorDir
		files, err = ioutil.ReadDir(pluginPath)
		if err != nil {
			return "", err
		}
	}
	providerFilePath := ""
	for _, file := range files {
		if file.IsDir() {
			continue
		}
		if strings.HasPrefix(file.Name(), "terraform-provider-"+providerName) {
			providerFilePath = pluginPath + string(os.PathSeparator) + file.Name()
		}
	}
	return providerFilePath, nil
}

func GetProviderVersion(providerName string) string {
	providerFilePath, err := getProviderFileName(providerName)
	if err != nil {
		log.Println("Can't find provider file path. Ensure that you are following https://www.terraform.io/docs/configuration/providers.html#third-party-plugins.")
		return ""
	}
	t := strings.Split(providerFilePath, string(os.PathSeparator))
	providerFileName := t[len(t)-1]
	providerFileNameParts := strings.Split(providerFileName, "_")
	if len(providerFileNameParts) < 2 {
		log.Println("Can't find provider version. Ensure that you are following https://www.terraform.io/docs/configuration/providers.html#plugin-names-and-versions.")
		return ""
	}
	providerVersion := providerFileNameParts[1]
	return "~>" + providerVersion
}
<commit_msg>add retry on read resources<commit_after>// Copyright 2018 The Terraformer 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 providerwrapper //nolint

import (
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"runtime"
	"strings"
	"time"

	"github.com/GoogleCloudPlatform/terraformer/terraformutils/terraformerstring"

	"github.com/zclconf/go-cty/cty"

	"github.com/hashicorp/go-hclog"
	"github.com/hashicorp/go-plugin"
	"github.com/hashicorp/terraform/configs/configschema"
	tfplugin "github.com/hashicorp/terraform/plugin"
	"github.com/hashicorp/terraform/providers"
	"github.com/hashicorp/terraform/terraform"
	"github.com/hashicorp/terraform/version"
)

// DefaultDataDir is the default directory for storing local data.
const DefaultDataDir = ".terraform"

// DefaultPluginVendorDir is the location in the config directory to look for
// user-added plugin binaries. Terraform only reads from this path if it
// exists, it is never created by terraform.
const DefaultPluginVendorDir = "terraform.d/plugins/" + pluginMachineName

// pluginMachineName is the directory name used in new plugin paths.
const pluginMachineName = runtime.GOOS + "_" + runtime.GOARCH

type ProviderWrapper struct {
	Provider     *tfplugin.GRPCProvider
	client       *plugin.Client
	rpcClient    plugin.ClientProtocol
	providerName string
	config       cty.Value
	schema       *providers.GetSchemaResponse
}

func NewProviderWrapper(providerName string, providerConfig cty.Value, verbose bool) (*ProviderWrapper, error) {
	p := &ProviderWrapper{}
	p.providerName = providerName
	p.config = providerConfig
	err := p.initProvider(verbose)

	return p, err
}

func (p *ProviderWrapper) Kill() {
	p.client.Kill()
}

func (p *ProviderWrapper) GetSchema() *providers.GetSchemaResponse {
	if p.schema == nil {
		r := p.Provider.GetSchema()
		p.schema = &r
	}
	return p.schema
}

func (p *ProviderWrapper) GetReadOnlyAttributes(resourceTypes []string) (map[string][]string, error) {
	r := p.GetSchema()

	if r.Diagnostics.HasErrors() {
		return nil, r.Diagnostics.Err()
	}
	readOnlyAttributes := map[string][]string{}
	for resourceName, obj := range r.ResourceTypes {
		if terraformerstring.ContainsString(resourceTypes, resourceName) {
			readOnlyAttributes[resourceName] = append(readOnlyAttributes[resourceName], "^id$")
			for k, v := range obj.Block.Attributes {
				if !v.Optional && !v.Required {
					if v.Type.IsListType() || v.Type.IsSetType() {
						readOnlyAttributes[resourceName] = append(readOnlyAttributes[resourceName], "^"+k+".(.*)")
					} else {
						readOnlyAttributes[resourceName] = append(readOnlyAttributes[resourceName], "^"+k+"$")
					}
				}
			}
			readOnlyAttributes[resourceName] = p.readObjBlocks(obj.Block.BlockTypes, readOnlyAttributes[resourceName], "-1")
		}
	}
	return readOnlyAttributes, nil
}

func (p *ProviderWrapper) readObjBlocks(block map[string]*configschema.NestedBlock, readOnlyAttributes []string, parent string) []string {
	for k, v := range block {
		if len(v.BlockTypes) > 0 {
			readOnlyAttributes = p.readObjBlocks(v.BlockTypes, readOnlyAttributes, k)
		}
		fieldCount := 0
		for key, l := range v.Attributes {
			if !l.Optional && !l.Required {
				fieldCount++
				switch v.Nesting {
				case configschema.NestingList:
					if parent == "-1" {
						readOnlyAttributes = append(readOnlyAttributes, "^"+k+".[0-9]."+key+"($|\\.[0-9]|\\.#)")
					} else {
						readOnlyAttributes = append(readOnlyAttributes, "^"+parent+".(.*)."+key+"$")
					}
				case configschema.NestingSet:
					if parent == "-1" {
						readOnlyAttributes = append(readOnlyAttributes, "^"+k+".[0-9]."+key+"$")
					} else {
						readOnlyAttributes = append(readOnlyAttributes, "^"+parent+".(.*)."+key+"($|\\.(.*))")
					}
				case configschema.NestingMap:
					readOnlyAttributes = append(readOnlyAttributes, parent+"."+key)
				default:
					readOnlyAttributes = append(readOnlyAttributes, parent+"."+key+"$")
				}
			}
		}
		if fieldCount == len(v.Block.Attributes) && fieldCount > 0 {
			readOnlyAttributes = append(readOnlyAttributes, "^"+k)
		}
	}
	return readOnlyAttributes
}

func (p *ProviderWrapper) Refresh(info *terraform.InstanceInfo, state *terraform.InstanceState) (*terraform.InstanceState, error) {
	schema := p.GetSchema()
	impliedType := schema.ResourceTypes[info.Type].Block.ImpliedType()
	priorState, err := state.AttrsAsObjectValue(impliedType)
	if err != nil {
		return nil, err
	}
	successReadResource := false
	resp := providers.ReadResourceResponse{}
	for i := 0; i < 5; i++ {
		resp = p.Provider.ReadResource(providers.ReadResourceRequest{
			TypeName:   info.Type,
			PriorState: priorState,
			Private:    []byte{},
		})
		if resp.Diagnostics.HasErrors() {
			log.Println("WARN: Fail read resource from provider, wait 300ms before retry")
			time.Sleep(300 * time.Millisecond)
			continue
		} else {
			successReadResource = true
			break
		}
	}

	if !successReadResource {
		log.Println("Fail read resource from provider, trying import command")
		// retry with regular import command - without resource attributes
		importResponse := p.Provider.ImportResourceState(providers.ImportResourceStateRequest{
			TypeName: info.Type,
			ID:       state.ID,
		})
		if importResponse.Diagnostics.HasErrors() {
			return nil, resp.Diagnostics.Err()
		}
		if len(importResponse.ImportedResources) == 0 {
			return nil, errors.New("not able to import resource for a given ID")
		}
		return terraform.NewInstanceStateShimmedFromValue(importResponse.ImportedResources[0].State, int(schema.ResourceTypes[info.Type].Version)), nil
	}

	if resp.NewState.IsNull() {
		msg := fmt.Sprintf("ERROR: Read resource response is null for resource %s", info.Id)
		return nil, errors.New(msg)
	}

	return terraform.NewInstanceStateShimmedFromValue(resp.NewState, int(schema.ResourceTypes[info.Type].Version)), nil
}

func (p *ProviderWrapper) initProvider(verbose bool) error {
	providerFilePath, err := getProviderFileName(p.providerName)
	if err != nil {
		return err
	}
	options := hclog.LoggerOptions{
		Name:   "plugin",
		Level:  hclog.Error,
		Output: os.Stdout,
	}
	if verbose {
		options.Level = hclog.Trace
	}
	logger := hclog.New(&options)
	p.client = plugin.NewClient(
		&plugin.ClientConfig{
			Cmd:              exec.Command(providerFilePath),
			HandshakeConfig:  tfplugin.Handshake,
			VersionedPlugins: tfplugin.VersionedPlugins,
			Managed:          true,
			Logger:           logger,
			AllowedProtocols: []plugin.Protocol{plugin.ProtocolGRPC},
			AutoMTLS:         true,
		})
	p.rpcClient, err = p.client.Client()
	if err != nil {
		return err
	}
	raw, err := p.rpcClient.Dispense(tfplugin.ProviderPluginName)
	if err != nil {
		return err
	}

	p.Provider = raw.(*tfplugin.GRPCProvider)

	config, err := p.GetSchema().Provider.Block.CoerceValue(p.config)
	if err != nil {
		return err
	}
	p.Provider.Configure(providers.ConfigureRequest{
		TerraformVersion: version.Version,
		Config:           config,
	})

	return nil
}

func getProviderFileName(providerName string) (string, error) {
	defaultDataDir := os.Getenv("TF_DATA_DIR")
	if defaultDataDir == "" {
		defaultDataDir = DefaultDataDir
	}
	pluginPath := defaultDataDir + string(os.PathSeparator) + "plugins" + string(os.PathSeparator) + runtime.GOOS + "_" + runtime.GOARCH
	files, err := ioutil.ReadDir(pluginPath)
	if err != nil {
		pluginPath = os.Getenv("HOME") + string(os.PathSeparator) + "." + DefaultPluginVendorDir
		files, err = ioutil.ReadDir(pluginPath)
		if err != nil {
			return "", err
		}
	}
	providerFilePath := ""
	for _, file := range files {
		if file.IsDir() {
			continue
		}
		if strings.HasPrefix(file.Name(), "terraform-provider-"+providerName) {
			providerFilePath = pluginPath + string(os.PathSeparator) + file.Name()
		}
	}
	return providerFilePath, nil
}

func GetProviderVersion(providerName string) string {
	providerFilePath, err := getProviderFileName(providerName)
	if err != nil {
		log.Println("Can't find provider file path. Ensure that you are following https://www.terraform.io/docs/configuration/providers.html#third-party-plugins.")
		return ""
	}
	t := strings.Split(providerFilePath, string(os.PathSeparator))
	providerFileName := t[len(t)-1]
	providerFileNameParts := strings.Split(providerFileName, "_")
	if len(providerFileNameParts) < 2 {
		log.Println("Can't find provider version. Ensure that you are following https://www.terraform.io/docs/configuration/providers.html#plugin-names-and-versions.")
		return ""
	}
	providerVersion := providerFileNameParts[1]
	return "~>" + providerVersion
}
<|endoftext|>