<commit_before>package state_test

import (
	. "launchpad.net/gocheck"
	"launchpad.net/juju-core/state"
)

type RelationSuite struct {
	ConnSuite
	charm *state.Charm
}

var _ = Suite(&RelationSuite{})

func (s *RelationSuite) SetUpTest(c *C) {
	s.ConnSuite.SetUpTest(c)
	s.charm = s.AddTestingCharm(c, "dummy")
}

func (s *RelationSuite) TestAddRelationErrors(c *C) {
	req, err := s.State.AddService("req", s.charm)
	c.Assert(err, IsNil)
	reqep := state.RelationEndpoint{"req", "ifce", "bar", state.RoleRequirer, state.ScopeGlobal}

	// Check we can't add a relation until both services exist.
	proep := state.RelationEndpoint{"pro", "ifce", "foo", state.RoleProvider, state.ScopeGlobal}
	err = s.State.AddRelation(proep, reqep)
	c.Assert(err, ErrorMatches, `can't add relation "pro:foo req:bar": service with name "pro" not found`)
	assertNoRelations(c, req)
	pro, err := s.State.AddService("pro", s.charm)
	c.Assert(err, IsNil)

	// Check that interfaces have to match.
	proep2 := state.RelationEndpoint{"pro", "other", "foo", state.RoleProvider, state.ScopeGlobal}
	err = s.State.AddRelation(proep2, reqep)
	c.Assert(err, ErrorMatches, `can't add relation "pro:foo req:bar": endpoints do not relate`)
	assertNoRelations(c, pro)
	assertNoRelations(c, req)

	// Check a variety of surprising endpoint combinations.
	err = s.State.AddRelation(reqep)
	c.Assert(err, ErrorMatches, `can't add relation "req:bar": single endpoint must be a peer relation`)
	assertNoRelations(c, req)

	peer, err := s.State.AddService("peer", s.charm)
	c.Assert(err, IsNil)
	peerep := state.RelationEndpoint{"peer", "ifce", "baz", state.RolePeer, state.ScopeGlobal}
	err = s.State.AddRelation(peerep, reqep)
	c.Assert(err, ErrorMatches, `can't add relation "peer:baz req:bar": endpoints do not relate`)
	assertNoRelations(c, peer)
	assertNoRelations(c, req)

	err = s.State.AddRelation(peerep, peerep)
	c.Assert(err, ErrorMatches, `can't add relation "peer:baz peer:baz": endpoints do not relate`)
	assertNoRelations(c, peer)

	err = s.State.AddRelation()
	c.Assert(err, ErrorMatches, `can't add relation "": can't relate 0 endpoints`)
	err = s.State.AddRelation(proep, reqep, peerep)
	c.Assert(err, ErrorMatches, `can't add relation "pro:foo req:bar peer:baz": can't relate 3 endpoints`)
}

func (s *RelationSuite) TestProviderRequirerRelation(c *C) {
	req, err := s.State.AddService("req", s.charm)
	c.Assert(err, IsNil)
	pro, err := s.State.AddService("pro", s.charm)
	c.Assert(err, IsNil)
	assertNoRelations(c, req)
	assertNoRelations(c, pro)

	// Add a relation, and check we can only do so once.
	proep := state.RelationEndpoint{"pro", "ifce", "foo", state.RoleProvider, state.ScopeGlobal}
	reqep := state.RelationEndpoint{"req", "ifce", "bar", state.RoleRequirer, state.ScopeGlobal}
	err = s.State.AddRelation(proep, reqep)
	c.Assert(err, IsNil)
	err = s.State.AddRelation(proep, reqep)
	c.Assert(err, ErrorMatches, `can't add relation "pro:foo req:bar": relation already exists`)
	assertOneRelation(c, pro, 0, proep, reqep)
	assertOneRelation(c, req, 0, reqep, proep)

	// Remove the relation, and check it can't be removed again.
	err = s.State.RemoveRelation(proep, reqep)
	c.Assert(err, IsNil)
	assertNoRelations(c, pro)
	assertNoRelations(c, req)
	err = s.State.RemoveRelation(proep, reqep)
	c.Assert(err, ErrorMatches, `can't remove relation "pro:foo req:bar": relation doesn't exist`)

	// Check that we can add it again if we want to; but this time,
	// give one of the endpoints container scope and check that both
	// resulting service relations get that scope.
	reqep.RelationScope = state.ScopeContainer
	err = s.State.AddRelation(proep, reqep)
	c.Assert(err, IsNil)
	// After adding relation, make proep container-scoped as well, for
	// simplicity of testing.
	proep.RelationScope = state.ScopeContainer
	assertOneRelation(c, pro, 1, proep, reqep)
	assertOneRelation(c, req, 1, reqep, proep)
}

func (s *RelationSuite) TestPeerRelation(c *C) {
	peer, err := s.State.AddService("peer", s.charm)
	c.Assert(err, IsNil)
	peerep := state.RelationEndpoint{"peer", "ifce", "baz", state.RolePeer, state.ScopeGlobal}
	assertNoRelations(c, peer)

	// Add a relation, and check we can only do so once.
	err = s.State.AddRelation(peerep)
	c.Assert(err, IsNil)
	err = s.State.AddRelation(peerep)
	c.Assert(err, ErrorMatches, `can't add relation "peer:baz": relation already exists`)
	assertOneRelation(c, peer, 0, peerep)

	// Remove the relation, and check it can't be removed again.
	err = s.State.RemoveRelation(peerep)
	c.Assert(err, IsNil)
	assertNoRelations(c, peer)
	err = s.State.RemoveRelation(peerep)
	c.Assert(err, ErrorMatches, `can't remove relation "peer:baz": relation doesn't exist`)
}

func assertNoRelations(c *C, srv *state.Service) {
	rels, err := srv.Relations()
	c.Assert(err, IsNil)
	c.Assert(rels, HasLen, 0)
}

func assertOneRelation(c *C, srv *state.Service, relId int, endpoints ...state.RelationEndpoint) {
	rels, err := srv.Relations()
	c.Assert(err, IsNil)
	c.Assert(rels, HasLen, 1)
	rel := rels[0]
	c.Assert(rel.Id(), Equals, relId)
	name := srv.Name()
	expectEp := endpoints[0]
	ep, err := rel.Endpoint(name)
	c.Assert(err, IsNil)
	c.Assert(ep, DeepEquals, expectEp)
	if len(endpoints) == 2 {
		expectEp = endpoints[1]
	}
	eps, err := rel.RelatedEndpoints(name)
	c.Assert(err, IsNil)
	c.Assert(eps, DeepEquals, []state.RelationEndpoint{expectEp})
}
<commit_msg>repurpose RelationUnit test for peer relations from relation-unit branch<commit_after>package state_test

import (
	"fmt"
	. "launchpad.net/gocheck"
	"launchpad.net/juju-core/state"
	"launchpad.net/juju-core/state/presence"
	"time"
)

type RelationSuite struct {
	ConnSuite
	charm *state.Charm
}

var _ = Suite(&RelationSuite{})

func (s *RelationSuite) SetUpTest(c *C) {
	s.ConnSuite.SetUpTest(c)
	s.charm = s.AddTestingCharm(c, "dummy")
}

func (s *RelationSuite) TestAddRelationErrors(c *C) {
	req, err := s.State.AddService("req", s.charm)
	c.Assert(err, IsNil)
	reqep := state.RelationEndpoint{"req", "ifce", "bar", state.RoleRequirer, state.ScopeGlobal}

	// Check we can't add a relation until both services exist.
	proep := state.RelationEndpoint{"pro", "ifce", "foo", state.RoleProvider, state.ScopeGlobal}
	err = s.State.AddRelation(proep, reqep)
	c.Assert(err, ErrorMatches, `can't add relation "pro:foo req:bar": service with name "pro" not found`)
	assertNoRelations(c, req)
	pro, err := s.State.AddService("pro", s.charm)
	c.Assert(err, IsNil)

	// Check that interfaces have to match.
	proep2 := state.RelationEndpoint{"pro", "other", "foo", state.RoleProvider, state.ScopeGlobal}
	err = s.State.AddRelation(proep2, reqep)
	c.Assert(err, ErrorMatches, `can't add relation "pro:foo req:bar": endpoints do not relate`)
	assertNoRelations(c, pro)
	assertNoRelations(c, req)

	// Check a variety of surprising endpoint combinations.
	err = s.State.AddRelation(reqep)
	c.Assert(err, ErrorMatches, `can't add relation "req:bar": single endpoint must be a peer relation`)
	assertNoRelations(c, req)

	peer, err := s.State.AddService("peer", s.charm)
	c.Assert(err, IsNil)
	peerep := state.RelationEndpoint{"peer", "ifce", "baz", state.RolePeer, state.ScopeGlobal}
	err = s.State.AddRelation(peerep, reqep)
	c.Assert(err, ErrorMatches, `can't add relation "peer:baz req:bar": endpoints do not relate`)
	assertNoRelations(c, peer)
	assertNoRelations(c, req)

	err = s.State.AddRelation(peerep, peerep)
	c.Assert(err, ErrorMatches, `can't add relation "peer:baz peer:baz": endpoints do not relate`)
	assertNoRelations(c, peer)

	err = s.State.AddRelation()
	c.Assert(err, ErrorMatches, `can't add relation "": can't relate 0 endpoints`)
	err = s.State.AddRelation(proep, reqep, peerep)
	c.Assert(err, ErrorMatches, `can't add relation "pro:foo req:bar peer:baz": can't relate 3 endpoints`)
}

func (s *RelationSuite) TestProviderRequirerRelation(c *C) {
	req, err := s.State.AddService("req", s.charm)
	c.Assert(err, IsNil)
	pro, err := s.State.AddService("pro", s.charm)
	c.Assert(err, IsNil)
	assertNoRelations(c, req)
	assertNoRelations(c, pro)

	// Add a relation, and check we can only do so once.
	proep := state.RelationEndpoint{"pro", "ifce", "foo", state.RoleProvider, state.ScopeGlobal}
	reqep := state.RelationEndpoint{"req", "ifce", "bar", state.RoleRequirer, state.ScopeGlobal}
	err = s.State.AddRelation(proep, reqep)
	c.Assert(err, IsNil)
	err = s.State.AddRelation(proep, reqep)
	c.Assert(err, ErrorMatches, `can't add relation "pro:foo req:bar": relation already exists`)
	assertOneRelation(c, pro, 0, proep, reqep)
	assertOneRelation(c, req, 0, reqep, proep)

	// Remove the relation, and check it can't be removed again.
	err = s.State.RemoveRelation(proep, reqep)
	c.Assert(err, IsNil)
	assertNoRelations(c, pro)
	assertNoRelations(c, req)
	err = s.State.RemoveRelation(proep, reqep)
	c.Assert(err, ErrorMatches, `can't remove relation "pro:foo req:bar": relation doesn't exist`)

	// Check that we can add it again if we want to; but this time,
	// give one of the endpoints container scope and check that both
	// resulting service relations get that scope.
	reqep.RelationScope = state.ScopeContainer
	err = s.State.AddRelation(proep, reqep)
	c.Assert(err, IsNil)
	// After adding relation, make proep container-scoped as well, for
	// simplicity of testing.
	proep.RelationScope = state.ScopeContainer
	assertOneRelation(c, pro, 1, proep, reqep)
	assertOneRelation(c, req, 1, reqep, proep)
}

func (s *RelationSuite) TestPeerRelation(c *C) {
	peer, err := s.State.AddService("peer", s.charm)
	c.Assert(err, IsNil)
	peerep := state.RelationEndpoint{"peer", "ifce", "baz", state.RolePeer, state.ScopeGlobal}
	assertNoRelations(c, peer)

	// Add a relation, and check we can only do so once.
	err = s.State.AddRelation(peerep)
	c.Assert(err, IsNil)
	err = s.State.AddRelation(peerep)
	c.Assert(err, ErrorMatches, `can't add relation "peer:baz": relation already exists`)
	assertOneRelation(c, peer, 0, peerep)

	// Remove the relation, and check it can't be removed again.
	err = s.State.RemoveRelation(peerep)
	c.Assert(err, IsNil)
	assertNoRelations(c, peer)
	err = s.State.RemoveRelation(peerep)
	c.Assert(err, ErrorMatches, `can't remove relation "peer:baz": relation doesn't exist`)
}

func assertNoRelations(c *C, srv *state.Service) {
	rels, err := srv.Relations()
	c.Assert(err, IsNil)
	c.Assert(rels, HasLen, 0)
}

func assertOneRelation(c *C, srv *state.Service, relId int, endpoints ...state.RelationEndpoint) {
	rels, err := srv.Relations()
	c.Assert(err, IsNil)
	c.Assert(rels, HasLen, 1)
	rel := rels[0]
	c.Assert(rel.Id(), Equals, relId)
	name := srv.Name()
	expectEp := endpoints[0]
	ep, err := rel.Endpoint(name)
	c.Assert(err, IsNil)
	c.Assert(ep, DeepEquals, expectEp)
	if len(endpoints) == 2 {
		expectEp = endpoints[1]
	}
	eps, err := rel.RelatedEndpoints(name)
	c.Assert(err, IsNil)
	c.Assert(eps, DeepEquals, []state.RelationEndpoint{expectEp})
}

type RelationUnitSuite struct {
	ConnSuite
	charm *state.Charm
}

var _ = Suite(&RelationUnitSuite{})

func (s *RelationUnitSuite) SetUpTest(c *C) {
	s.ConnSuite.SetUpTest(c)
	s.charm = s.AddTestingCharm(c, "dummy")
}

func (s *RelationUnitSuite) TestPeerRelation(c *C) {
	peer, err := s.State.AddService("peer", s.charm)
	c.Assert(err, IsNil)
	peerep := state.RelationEndpoint{"peer", "ifce", "baz", state.RolePeer, state.ScopeGlobal}
	err = s.State.AddRelation(peerep)
	c.Assert(err, IsNil)

	// Add some units to the service and set their private addresses.
	// (Private addresses should be set by their unit agents on
	// startup; this test does not include that, but Join expects
	// the information to be available, and uses it to populate the
	// relation settings node.)
	units := []*state.Unit{}
	for i := 0; i < 3; i++ {
		unit, err := peer.AddUnit()
		c.Assert(err, IsNil)
		err = unit.SetPrivateAddress(fmt.Sprintf("peer%d.example.com", i))
		c.Assert(err, IsNil)
		units = append(units, unit)
	}

	// Get the peer relation.
	rels, err := peer.Relations()
	c.Assert(err, IsNil)
	c.Assert(rels, HasLen, 1)
	rel := rels[0]

	// ---------- Single unit ----------

	// Start watching the relation from the perspective of the first unit.
	w0, err := rel.Watch(units[0])
	c.Assert(err, IsNil)
	defer stop(c, w0)
	assertChange(c, w0, state.RelationUnitsChange{})
	assertNoChange(c, w0)

	// Join the first unit to the relation, and change the settings, and
	// check that nothing apparently happens.
	p0, err := rel.Join(units[0])
	c.Assert(err, IsNil)
	defer kill(c, p0)
	settings0 := changeSettings(c, rel, units[0])
	assertNoChange(c, w0)

	// ---------- Two units ----------

	// Now join another unit to the relation...
	p1, err := rel.Join(units[1])
	c.Assert(err, IsNil)
	defer kill(c, p1)

	// ...and check that the first relation unit sees the change.
	settings1, err := rel.Settings(units[1])
	c.Assert(err, IsNil)
	expect := state.RelationUnitsChange{Changed: map[string]state.UnitSettings{
		"peer/1": state.UnitSettings{0, settings1.Map()},
	}}
	assertChange(c, w0, expect)
	assertNoChange(c, w0)

	// Start watching the relation from the perspective of the second unit,
	// and check that it sees the right state.
	w1, err := rel.Watch(units[1])
	c.Assert(err, IsNil)
	defer stop(c, w1)
	expect = state.RelationUnitsChange{Changed: map[string]state.UnitSettings{
		"peer/0": state.UnitSettings{1, settings0.Map()},
	}}
	assertChange(c, w1, expect)
	assertNoChange(c, w1)

	// ---------- Three units ----------

	// Whoa, it works. Ok, check the third unit's opinion of the state.
	w2, err := rel.Watch(units[2])
	c.Assert(err, IsNil)
	defer stop(c, w2)
	expect = state.RelationUnitsChange{Changed: map[string]state.UnitSettings{
		"peer/0": state.UnitSettings{1, settings0.Map()},
		"peer/1": state.UnitSettings{0, settings1.Map()},
	}}
	assertChange(c, w2, expect)
	assertNoChange(c, w2)

	// Join the third unit, and check the first and second units see it.
	p2, err := rel.Join(units[2])
	c.Assert(err, IsNil)
	defer kill(c, p2)
	settings2, err := rel.Settings(units[2])
	c.Assert(err, IsNil)
	expect = state.RelationUnitsChange{Changed: map[string]state.UnitSettings{
		"peer/2": state.UnitSettings{0, settings2.Map()},
	}}
	assertChange(c, w0, expect)
	assertNoChange(c, w0)
	assertChange(c, w1, expect)
	assertNoChange(c, w1)

	// Change the second unit's settings, and check that only
	// the first and third see changes.
	settings1 = changeSettings(c, rel, units[1])
	assertNoChange(c, w1)
	expect = state.RelationUnitsChange{Changed: map[string]state.UnitSettings{
		"peer/1": state.UnitSettings{1, settings1.Map()},
	}}
	assertChange(c, w0, expect)
	assertNoChange(c, w0)
	assertChange(c, w2, expect)
	assertNoChange(c, w2)

	// ---------- Two units again ----------

	// Depart the second unit, and check that the first and third detect it.
	err = p1.Kill()
	c.Assert(err, IsNil)
	expect = state.RelationUnitsChange{Departed: []string{"peer/1"}}
	assertChange(c, w0, expect)
	assertNoChange(c, w0)
	assertChange(c, w2, expect)
	assertNoChange(c, w2)

	// Change its settings, and check the others don't observe anything.
	settings1 = changeSettings(c, rel, units[1])
	assertNoChange(c, w0)
	assertNoChange(c, w2)

	// Check no spurious events showed up on the second unit's watch, and check
	// it closes cleanly.
	assertNoChange(c, w1)
	err = w1.Stop()
	c.Assert(err, IsNil)
	assertClosed(c, w1)

	// ---------- One unit again, briefly  ----------

	// Cause the first unit to silently depart, then bring it back, and
	// check its watcher observes no changes...
	err = p0.Stop()
	c.Assert(err, IsNil)
	defer kill(c, p0)
	p0, err = rel.Join(units[0])
	c.Assert(err, IsNil)
	defer kill(c, p0)
	assertNoChange(c, w0)

	// ...then check that the third unit didn't notice anything either.
	// Note that joining should have caused the private address to
	// be set again, but this should not cause an actual *change*
	// in the settings, so nothing should actually have been written,
	// and thus nothing should have been detected.
	assertNoChange(c, w2)

	// OK, we're done here. Cleanup, and error detection during same,
	// will be handled by the deferred depart() calls. Phew.
}

func kill(c *C, p *presence.Pinger) {
	select {
	case <-p.Dying():
	default:
		c.Assert(p.Kill(), IsNil)
	}
}

func stop(c *C, w *state.RelationUnitsWatcher) {
	select {
	case <-w.Dying():
	default:
		c.Assert(w.Stop(), IsNil)
	}
}

func changeSettings(c *C, r *state.Relation, u *state.Unit) *state.ConfigNode {
	node, err := r.Settings(u)
	c.Assert(err, IsNil)
	value, _ := node.Get("value")
	v, _ := value.(int)
	node.Set("value", v+1)
	_, err = node.Write()
	c.Assert(err, IsNil)
	return node
}

func assertChange(c *C, w *state.RelationUnitsWatcher, expect state.RelationUnitsChange) {
	select {
	case ch, ok := <-w.Changes():
		c.Assert(ok, Equals, true)
		c.Assert(ch, DeepEquals, expect)
	case <-time.After(1000 * time.Millisecond):
		c.Fatalf("expected %#v, got nothing", expect)
	}
}

func assertNoChange(c *C, w *state.RelationUnitsWatcher) {
	select {
	case ch := <-w.Changes():
		c.Fatalf("got %#v, expected nothing", ch)
	case <-time.After(200 * time.Millisecond):
	}
}

func assertClosed(c *C, w *state.RelationUnitsWatcher) {
	select {
	case _, ok := <-w.Changes():
		c.Assert(ok, Equals, false)
	default:
	}
}
<|endoftext|>


<commit_before>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2016 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package influxdb

import (
	"errors"
	"github.com/influxdata/influxdb/client/v2"
	"net/url"
	"strconv"
	"time"
)

var (
	ErrNoDatabase = errors.New("influxdb output: no database specified")
)

func parseURL(u *url.URL) (client.Client, client.BatchPointsConfig, error) {
	batchConf, err := makeBatchConfigFromURL(u)
	if err != nil {
		return nil, client.BatchPointsConfig{}, err
	}

	if u.Scheme == "udp" {
		conf, err := makeUDPConfigFromURL(u)
		if err != nil {
			return nil, batchConf, err
		}
		c, err := client.NewUDPClient(conf)
		if err != nil {
			return nil, batchConf, err
		}
		return c, batchConf, nil
	}

	conf, err := makeHTTPConfigFromURL(u)
	if err != nil {
		return nil, batchConf, err
	}
	c, err := client.NewHTTPClient(conf)
	if err != nil {
		return nil, batchConf, err
	}
	return c, batchConf, nil
}

func makeUDPConfigFromURL(u *url.URL) (client.UDPConfig, error) {
	payloadSize := 0
	payloadSizeS := u.Query().Get("payload_size")
	if payloadSizeS != "" {
		s, err := strconv.ParseInt(payloadSizeS, 10, 32)
		if err != nil {
			return client.UDPConfig{}, err
		}
		payloadSize = int(s)
	}

	return client.UDPConfig{
		Addr:        u.Host,
		PayloadSize: payloadSize,
	}, nil
}

func makeHTTPConfigFromURL(u *url.URL) (client.HTTPConfig, error) {
	q := u.Query()

	username := ""
	password := ""
	if u.User != nil {
		username = u.User.Username()
		password, _ = u.User.Password()
	}

	timeout := 0 * time.Second
	if ts := q.Get("timeout"); ts != "" {
		t, err := time.ParseDuration(ts)
		if err != nil {
			return client.HTTPConfig{}, err
		}
		timeout = t
	}
	insecureSkipVerify := q.Get("insecure_skip_verify") != ""

	return client.HTTPConfig{
		Addr:               u.Scheme + "://" + u.Host,
		Username:           username,
		Password:           password,
		Timeout:            timeout,
		InsecureSkipVerify: insecureSkipVerify,
	}, nil
}

func makeBatchConfigFromURL(u *url.URL) (client.BatchPointsConfig, error) {
	if u.Path == "" || u.Path == "/" {
		return client.BatchPointsConfig{}, ErrNoDatabase
	}

	q := u.Query()
	return client.BatchPointsConfig{
		Database:         u.Path[1:], // strip leading "/"
		Precision:        q.Get("precision"),
		RetentionPolicy:  q.Get("retention_policy"),
		WriteConsistency: q.Get("write_consistency"),
	}, nil
}
<commit_msg>Create specificed db if it doesn't exist<commit_after>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2016 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package influxdb

import (
	"errors"
	"github.com/influxdata/influxdb/client/v2"
	"net/url"
	"strconv"
	"time"
)

var (
	ErrNoDatabase = errors.New("influxdb output: no database specified")
)

func parseURL(u *url.URL) (client.Client, client.BatchPointsConfig, error) {
	batchConf, err := makeBatchConfigFromURL(u)
	if err != nil {
		return nil, client.BatchPointsConfig{}, err
	}

	if u.Scheme == "udp" {
		conf, err := makeUDPConfigFromURL(u)
		if err != nil {
			return nil, batchConf, err
		}
		c, err := client.NewUDPClient(conf)
		if err != nil {
			return nil, batchConf, err
		}
		return c, batchConf, nil
	}

	conf, err := makeHTTPConfigFromURL(u)
	if err != nil {
		return nil, batchConf, err
	}
	c, err := client.NewHTTPClient(conf)
	if err != nil {
		return nil, batchConf, err
	}

	// Create database if it does not exist
	q := client.NewQuery("CREATE DATABASE "+batchConf.Database, "", "")
	_, err = c.Query(q)
	if err != nil {
		return nil, batchConf, err
	}

	return c, batchConf, nil
}

func makeUDPConfigFromURL(u *url.URL) (client.UDPConfig, error) {
	payloadSize := 0
	payloadSizeS := u.Query().Get("payload_size")
	if payloadSizeS != "" {
		s, err := strconv.ParseInt(payloadSizeS, 10, 32)
		if err != nil {
			return client.UDPConfig{}, err
		}
		payloadSize = int(s)
	}

	return client.UDPConfig{
		Addr:        u.Host,
		PayloadSize: payloadSize,
	}, nil
}

func makeHTTPConfigFromURL(u *url.URL) (client.HTTPConfig, error) {
	q := u.Query()

	username := ""
	password := ""
	if u.User != nil {
		username = u.User.Username()
		password, _ = u.User.Password()
	}

	timeout := 0 * time.Second
	if ts := q.Get("timeout"); ts != "" {
		t, err := time.ParseDuration(ts)
		if err != nil {
			return client.HTTPConfig{}, err
		}
		timeout = t
	}
	insecureSkipVerify := q.Get("insecure_skip_verify") != ""

	return client.HTTPConfig{
		Addr:               u.Scheme + "://" + u.Host,
		Username:           username,
		Password:           password,
		Timeout:            timeout,
		InsecureSkipVerify: insecureSkipVerify,
	}, nil
}

func makeBatchConfigFromURL(u *url.URL) (client.BatchPointsConfig, error) {
	if u.Path == "" || u.Path == "/" {
		return client.BatchPointsConfig{}, ErrNoDatabase
	}

	q := u.Query()
	return client.BatchPointsConfig{
		Database:         u.Path[1:], // strip leading "/"
		Precision:        q.Get("precision"),
		RetentionPolicy:  q.Get("retention_policy"),
		WriteConsistency: q.Get("write_consistency"),
	}, nil
}
<|endoftext|>


<commit_before>package mongo

import "github.com/BluePecker/JwtAuth/storage/driver"

type Mongo struct {

}

func init() {
    driver.Register("redis", &Mongo{})
}<commit_msg>fix bug<commit_after>package mongo

import (
    "github.com/BluePecker/JwtAuth/storage"
)

type Mongo struct {

}

func init() {
    storage.Register("mongo", &Mongo{})
}<|endoftext|>


<commit_before>/*
Copyright 2019 The Vitess 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 vreplsuite

import (
	"context"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strings"
	"testing"
	"time"

	"vitess.io/vitess/go/mysql"
	"vitess.io/vitess/go/sqltypes"
	"vitess.io/vitess/go/vt/schema"

	"vitess.io/vitess/go/test/endtoend/cluster"
	"vitess.io/vitess/go/test/endtoend/onlineddl"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

var (
	clusterInstance         *cluster.LocalProcessCluster
	vtParams                mysql.ConnParams
	evaluatedMysqlParams    *mysql.ConnParams
	ddlStrategy             = "online -skip-topo -vreplication-test-suite"
	executeStrategy         = "vtgate"
	waitForMigrationTimeout = 20 * time.Second

	hostname              = "localhost"
	keyspaceName          = "ks"
	cell                  = "zone1"
	schemaChangeDirectory = ""
	tableName             = `onlineddl_test`
	beforeTableName       = `onlineddl_test_before`
	afterTableName        = `onlineddl_test_after`
	eventName             = `onlineddl_test`
)

const (
	testDataPath   = "testdata"
	defaultSQLMode = "ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"
)

func TestMain(m *testing.M) {
	defer cluster.PanicHandler(nil)
	flag.Parse()

	exitcode, err := func() (int, error) {
		clusterInstance = cluster.NewCluster(cell, hostname)
		schemaChangeDirectory = path.Join("/tmp", fmt.Sprintf("schema_change_dir_%d", clusterInstance.GetAndReserveTabletUID()))
		defer os.RemoveAll(schemaChangeDirectory)
		defer clusterInstance.Teardown()

		if _, err := os.Stat(schemaChangeDirectory); os.IsNotExist(err) {
			_ = os.Mkdir(schemaChangeDirectory, 0700)
		}

		clusterInstance.VtctldExtraArgs = []string{
			"-schema_change_dir", schemaChangeDirectory,
			"-schema_change_controller", "local",
			"-schema_change_check_interval", "1",
			"-online_ddl_check_interval", "2s",
		}

		clusterInstance.VtTabletExtraArgs = []string{
			"-enable-lag-throttler",
			"-throttle_threshold", "1s",
			"-heartbeat_enable",
			"-heartbeat_interval", "250ms",
			"-migration_check_interval", "5s",
		}

		if err := clusterInstance.StartTopo(); err != nil {
			return 1, err
		}

		// Start keyspace
		keyspace := &cluster.Keyspace{
			Name: keyspaceName,
		}

		// No need for replicas in this stress test
		if err := clusterInstance.StartKeyspace(*keyspace, []string{"1"}, 0, false); err != nil {
			return 1, err
		}

		vtgateInstance := clusterInstance.NewVtgateInstance()
		// set the gateway we want to use
		vtgateInstance.GatewayImplementation = "tabletgateway"
		// Start vtgate
		if err := vtgateInstance.Setup(); err != nil {
			return 1, err
		}
		// ensure it is torn down during cluster TearDown
		clusterInstance.VtgateProcess = *vtgateInstance
		vtParams = mysql.ConnParams{
			Host: clusterInstance.Hostname,
			Port: clusterInstance.VtgateMySQLPort,
		}

		return m.Run(), nil
	}()
	if err != nil {
		fmt.Printf("%v\n", err)
		os.Exit(1)
	} else {
		os.Exit(exitcode)
	}

}

func TestSchemaChange(t *testing.T) {
	defer cluster.PanicHandler(t)

	shards := clusterInstance.Keyspaces[0].Shards
	require.Equal(t, 1, len(shards))

	files, err := ioutil.ReadDir(testDataPath)
	require.NoError(t, err)
	for _, f := range files {
		if !f.IsDir() {
			continue
		}
		// this is a test!
		t.Run(f.Name(), func(t *testing.T) {
			testSingle(t, f.Name())
		})
	}
}

func readTestFile(t *testing.T, testName string, fileName string) (content string, exists bool) {
	filePath := path.Join(testDataPath, testName, fileName)
	_, err := os.Stat(filePath)
	if os.IsNotExist(err) {
		return "", false
	}
	require.NoError(t, err)
	b, err := ioutil.ReadFile(filePath)
	require.NoError(t, err)
	return strings.TrimSpace(string(b)), true
}

func testSingle(t *testing.T, testName string) {
	sqlMode := defaultSQLMode
	if overrideSQLMode, exists := readTestFile(t, testName, "sql_mode"); exists {
		sqlMode = overrideSQLMode
	}
	sqlModeQuery := fmt.Sprintf("set @@global.sql_mode='%s'", sqlMode)
	_ = mysqlExec(t, sqlModeQuery, "")
	_ = mysqlExec(t, "set @@global.event_scheduler=1", "")

	_ = mysqlExec(t, fmt.Sprintf("drop table if exists %s, %s, %s", tableName, beforeTableName, afterTableName), "")
	_ = mysqlExec(t, fmt.Sprintf("drop event if exists %s", eventName), "")

	{
		// create
		f := "create.sql"
		_, exists := readTestFile(t, testName, f)
		require.True(t, exists)
		mysqlClientExecFile(t, testName, f)
	}

	var migrationMessage string
	var migrationStatus string
	// Run test
	alterClause := "engine=innodb"
	if content, exists := readTestFile(t, testName, "alter"); exists {
		alterClause = content
	}
	alterStatement := fmt.Sprintf("alter table %s %s", tableName, alterClause)
	uuid := testOnlineDDLStatement(t, alterStatement, ddlStrategy, executeStrategy)
	row := waitForMigration(t, uuid, waitForMigrationTimeout)
	// migration is complete
	{
		migrationStatus = row["migration_status"].ToString()
		migrationMessage = row["message"].ToString()
	}
	{
		// destroy
		f := "destroy.sql"
		if _, exists := readTestFile(t, testName, f); exists {
			mysqlClientExecFile(t, testName, f)
		}
	}

	if expectedErrorMessage, exists := readTestFile(t, testName, "expect_failure"); exists {
		// Failure is expected!
		assert.Equal(t, migrationStatus, string(schema.OnlineDDLStatusFailed))
		require.Contains(t, migrationMessage, expectedErrorMessage, "expected error message (%s) to contain (%s)", migrationMessage, expectedErrorMessage)
		// no need to proceed to checksum or anything further
		return
	}
	// We do not expect failure.
	require.Equal(t, migrationStatus, string(schema.OnlineDDLStatusComplete))

	if content, exists := readTestFile(t, testName, "expect_table_structure"); exists {
		createStatement := getCreateTableStatement(t, tableName)
		assert.Contains(t, createStatement, content, "expected SHOW CREATE TABLE to contain text in 'expect_table_structure' file")
	}

	{
		// checksum
		beforeColumns := "*"
		if content, exists := readTestFile(t, testName, "before_columns"); exists {
			beforeColumns = content
		}
		afterColumns := "*"
		if content, exists := readTestFile(t, testName, "after_columns"); exists {
			afterColumns = content
		}
		orderBy := ""
		if content, exists := readTestFile(t, testName, "order_by"); exists {
			orderBy = fmt.Sprintf("order by %s", content)
		}
		selectBefore := fmt.Sprintf("select %s from %s %s", beforeColumns, beforeTableName, orderBy)
		selectAfter := fmt.Sprintf("select %s from %s %s", afterColumns, afterTableName, orderBy)

		selectBeforeRS := mysqlExec(t, selectBefore, "")
		selectAfterRS := mysqlExec(t, selectAfter, "")

		require.Equal(t, selectBeforeRS.Rows, selectAfterRS.Rows, "results mismatch: (%s) amd (%s)", selectBefore, selectAfter)
		// selectBeforeFile := createTempScript(t, selectBefore)
		// selectAfterFile := createTempScript(t, selectAfter)

	}
}

// testOnlineDDLStatement runs an online DDL, ALTER statement
func testOnlineDDLStatement(t *testing.T, alterStatement string, ddlStrategy string, executeStrategy string) (uuid string) {
	if executeStrategy == "vtgate" {
		row := onlineddl.VtgateExecDDL(t, &vtParams, ddlStrategy, alterStatement, "").Named().Row()
		if row != nil {
			uuid = row.AsString("uuid", "")
		}
	} else {
		var err error
		uuid, err = clusterInstance.VtctlclientProcess.ApplySchemaWithOutput(keyspaceName, alterStatement, cluster.VtctlClientParams{DDLStrategy: ddlStrategy})
		assert.NoError(t, err)
	}
	uuid = strings.TrimSpace(uuid)

	return uuid
}

func readMigration(t *testing.T, uuid string) sqltypes.RowNamedValues {
	rs := onlineddl.ReadMigrations(t, &vtParams, uuid)
	require.NotNil(t, rs)
	row := rs.Named().Row()
	require.NotNil(t, row)
	return row
}

func waitForMigration(t *testing.T, uuid string, timeout time.Duration) sqltypes.RowNamedValues {
	var status string
	sleepDuration := time.Second
	for timeout > 0 {
		row := readMigration(t, uuid)
		status = row["migration_status"].ToString()
		switch status {
		case string(schema.OnlineDDLStatusComplete), string(schema.OnlineDDLStatusFailed):
			// migration is complete, either successful or not
			return row
		}
		time.Sleep(sleepDuration)
		timeout = timeout - sleepDuration
	}
	require.NoError(t, fmt.Errorf("timeout in waitForMigration(%s). status is: %s", uuid, status))
	return nil
}

func getTablet() *cluster.Vttablet {
	return clusterInstance.Keyspaces[0].Shards[0].Vttablets[0]
}

func mysqlParams() *mysql.ConnParams {
	if evaluatedMysqlParams != nil {
		return evaluatedMysqlParams
	}
	evaluatedMysqlParams = &mysql.ConnParams{
		Uname:      "vt_dba",
		UnixSocket: path.Join(os.Getenv("VTDATAROOT"), fmt.Sprintf("/vt_%010d", getTablet().TabletUID), "/mysql.sock"),
		DbName:     fmt.Sprintf("vt_%s", keyspaceName),
	}
	return evaluatedMysqlParams
}

// VtgateExecDDL executes a DDL query with given strategy
func mysqlExec(t *testing.T, sql string, expectError string) *sqltypes.Result {
	t.Helper()

	ctx := context.Background()
	conn, err := mysql.Connect(ctx, mysqlParams())
	require.Nil(t, err)
	defer conn.Close()

	qr, err := conn.ExecuteFetch(sql, 100000, true)
	if expectError == "" {
		require.NoError(t, err)
	} else {
		require.Error(t, err, "error should not be nil")
		require.Contains(t, err.Error(), expectError, "Unexpected error")
	}
	return qr
}

// mysqlClientExecFile runs a file through the mysql client
func mysqlClientExecFile(t *testing.T, testName string, fileName string) (output string) {
	t.Helper()

	bashPath, err := exec.LookPath("bash")
	require.NoError(t, err)
	mysqlPath, err := exec.LookPath("mysql")
	require.NoError(t, err)
	filePath, _ := filepath.Abs(path.Join(testDataPath, testName, fileName))
	params := mysqlParams()
	bashCommand := fmt.Sprintf(`%s -u%s --socket=%s --database=%s < %s 2> /tmp/error.log`, mysqlPath, params.Uname, params.UnixSocket, params.DbName, filePath)
	cmd, err := exec.Command(
		bashPath,
		"-c",
		bashCommand,
	).Output()

	require.NoError(t, err)
	return string(cmd)
}

// getCreateTableStatement returns the CREATE TABLE statement for a given table
func getCreateTableStatement(t *testing.T, tableName string) (statement string) {
	queryResult, err := getTablet().VttabletProcess.QueryTablet(fmt.Sprintf("show create table %s", tableName), keyspaceName, true)
	require.Nil(t, err)

	assert.Equal(t, len(queryResult.Rows), 1)
	assert.Equal(t, len(queryResult.Rows[0]), 2) // table name, create statement
	statement = queryResult.Rows[0][1].ToString()
	return statement
}
<commit_msg>support ignore_versions flag file<commit_after>/*
Copyright 2019 The Vitess 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 vreplsuite

import (
	"context"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"regexp"
	"strings"
	"testing"
	"time"

	"vitess.io/vitess/go/mysql"
	"vitess.io/vitess/go/sqltypes"
	"vitess.io/vitess/go/vt/schema"

	"vitess.io/vitess/go/test/endtoend/cluster"
	"vitess.io/vitess/go/test/endtoend/onlineddl"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

var (
	clusterInstance         *cluster.LocalProcessCluster
	vtParams                mysql.ConnParams
	evaluatedMysqlParams    *mysql.ConnParams
	ddlStrategy             = "online -skip-topo -vreplication-test-suite"
	executeStrategy         = "vtgate"
	waitForMigrationTimeout = 20 * time.Second

	hostname              = "localhost"
	keyspaceName          = "ks"
	cell                  = "zone1"
	schemaChangeDirectory = ""
	tableName             = `onlineddl_test`
	beforeTableName       = `onlineddl_test_before`
	afterTableName        = `onlineddl_test_after`
	eventName             = `onlineddl_test`
)

const (
	testDataPath   = "testdata"
	defaultSQLMode = "ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"
)

func TestMain(m *testing.M) {
	defer cluster.PanicHandler(nil)
	flag.Parse()

	exitcode, err := func() (int, error) {
		clusterInstance = cluster.NewCluster(cell, hostname)
		schemaChangeDirectory = path.Join("/tmp", fmt.Sprintf("schema_change_dir_%d", clusterInstance.GetAndReserveTabletUID()))
		defer os.RemoveAll(schemaChangeDirectory)
		defer clusterInstance.Teardown()

		if _, err := os.Stat(schemaChangeDirectory); os.IsNotExist(err) {
			_ = os.Mkdir(schemaChangeDirectory, 0700)
		}

		clusterInstance.VtctldExtraArgs = []string{
			"-schema_change_dir", schemaChangeDirectory,
			"-schema_change_controller", "local",
			"-schema_change_check_interval", "1",
			"-online_ddl_check_interval", "2s",
		}

		clusterInstance.VtTabletExtraArgs = []string{
			"-enable-lag-throttler",
			"-throttle_threshold", "1s",
			"-heartbeat_enable",
			"-heartbeat_interval", "250ms",
			"-migration_check_interval", "5s",
		}

		if err := clusterInstance.StartTopo(); err != nil {
			return 1, err
		}

		// Start keyspace
		keyspace := &cluster.Keyspace{
			Name: keyspaceName,
		}

		// No need for replicas in this stress test
		if err := clusterInstance.StartKeyspace(*keyspace, []string{"1"}, 0, false); err != nil {
			return 1, err
		}

		vtgateInstance := clusterInstance.NewVtgateInstance()
		// set the gateway we want to use
		vtgateInstance.GatewayImplementation = "tabletgateway"
		// Start vtgate
		if err := vtgateInstance.Setup(); err != nil {
			return 1, err
		}
		// ensure it is torn down during cluster TearDown
		clusterInstance.VtgateProcess = *vtgateInstance
		vtParams = mysql.ConnParams{
			Host: clusterInstance.Hostname,
			Port: clusterInstance.VtgateMySQLPort,
		}

		return m.Run(), nil
	}()
	if err != nil {
		fmt.Printf("%v\n", err)
		os.Exit(1)
	} else {
		os.Exit(exitcode)
	}

}

func TestSchemaChange(t *testing.T) {
	defer cluster.PanicHandler(t)

	shards := clusterInstance.Keyspaces[0].Shards
	require.Equal(t, 1, len(shards))

	files, err := ioutil.ReadDir(testDataPath)
	require.NoError(t, err)
	for _, f := range files {
		if !f.IsDir() {
			continue
		}
		// this is a test!
		t.Run(f.Name(), func(t *testing.T) {
			testSingle(t, f.Name())
		})
	}
}

func readTestFile(t *testing.T, testName string, fileName string) (content string, exists bool) {
	filePath := path.Join(testDataPath, testName, fileName)
	_, err := os.Stat(filePath)
	if os.IsNotExist(err) {
		return "", false
	}
	require.NoError(t, err)
	b, err := ioutil.ReadFile(filePath)
	require.NoError(t, err)
	return strings.TrimSpace(string(b)), true
}

func testSingle(t *testing.T, testName string) {

	if ignoreVersions, exists := readTestFile(t, testName, "ignore_versions"); exists {
		// ignoreVersions is a regexp
		re, err := regexp.Compile(ignoreVersions)
		require.NoError(t, err)

		rs := mysqlExec(t, "select @@version as ver", "")
		row := rs.Named().Row()
		require.NotNil(t, row)
		mysqlVersion := row["ver"].ToString()

		if re.MatchString(mysqlVersion) {
			t.Skipf("Skipping test due to ignore_versions=%s", ignoreVersions)
			return
		}
	}

	sqlMode := defaultSQLMode
	if overrideSQLMode, exists := readTestFile(t, testName, "sql_mode"); exists {
		sqlMode = overrideSQLMode
	}
	sqlModeQuery := fmt.Sprintf("set @@global.sql_mode='%s'", sqlMode)
	_ = mysqlExec(t, sqlModeQuery, "")
	_ = mysqlExec(t, "set @@global.event_scheduler=1", "")

	_ = mysqlExec(t, fmt.Sprintf("drop table if exists %s, %s, %s", tableName, beforeTableName, afterTableName), "")
	_ = mysqlExec(t, fmt.Sprintf("drop event if exists %s", eventName), "")

	{
		// create
		f := "create.sql"
		_, exists := readTestFile(t, testName, f)
		require.True(t, exists)
		mysqlClientExecFile(t, testName, f)
	}

	var migrationMessage string
	var migrationStatus string
	// Run test
	alterClause := "engine=innodb"
	if content, exists := readTestFile(t, testName, "alter"); exists {
		alterClause = content
	}
	alterStatement := fmt.Sprintf("alter table %s %s", tableName, alterClause)
	uuid := testOnlineDDLStatement(t, alterStatement, ddlStrategy, executeStrategy)
	row := waitForMigration(t, uuid, waitForMigrationTimeout)
	// migration is complete
	{
		migrationStatus = row["migration_status"].ToString()
		migrationMessage = row["message"].ToString()
	}
	{
		// destroy
		f := "destroy.sql"
		if _, exists := readTestFile(t, testName, f); exists {
			mysqlClientExecFile(t, testName, f)
		}
	}

	if expectedErrorMessage, exists := readTestFile(t, testName, "expect_failure"); exists {
		// Failure is expected!
		assert.Equal(t, migrationStatus, string(schema.OnlineDDLStatusFailed))
		require.Contains(t, migrationMessage, expectedErrorMessage, "expected error message (%s) to contain (%s)", migrationMessage, expectedErrorMessage)
		// no need to proceed to checksum or anything further
		return
	}
	// We do not expect failure.
	require.Equal(t, migrationStatus, string(schema.OnlineDDLStatusComplete))

	if content, exists := readTestFile(t, testName, "expect_table_structure"); exists {
		createStatement := getCreateTableStatement(t, tableName)
		assert.Contains(t, createStatement, content, "expected SHOW CREATE TABLE to contain text in 'expect_table_structure' file")
	}

	{
		// checksum
		beforeColumns := "*"
		if content, exists := readTestFile(t, testName, "before_columns"); exists {
			beforeColumns = content
		}
		afterColumns := "*"
		if content, exists := readTestFile(t, testName, "after_columns"); exists {
			afterColumns = content
		}
		orderBy := ""
		if content, exists := readTestFile(t, testName, "order_by"); exists {
			orderBy = fmt.Sprintf("order by %s", content)
		}
		selectBefore := fmt.Sprintf("select %s from %s %s", beforeColumns, beforeTableName, orderBy)
		selectAfter := fmt.Sprintf("select %s from %s %s", afterColumns, afterTableName, orderBy)

		selectBeforeRS := mysqlExec(t, selectBefore, "")
		selectAfterRS := mysqlExec(t, selectAfter, "")

		require.Equal(t, selectBeforeRS.Rows, selectAfterRS.Rows, "results mismatch: (%s) amd (%s)", selectBefore, selectAfter)
		// selectBeforeFile := createTempScript(t, selectBefore)
		// selectAfterFile := createTempScript(t, selectAfter)

	}
}

// testOnlineDDLStatement runs an online DDL, ALTER statement
func testOnlineDDLStatement(t *testing.T, alterStatement string, ddlStrategy string, executeStrategy string) (uuid string) {
	if executeStrategy == "vtgate" {
		row := onlineddl.VtgateExecDDL(t, &vtParams, ddlStrategy, alterStatement, "").Named().Row()
		if row != nil {
			uuid = row.AsString("uuid", "")
		}
	} else {
		var err error
		uuid, err = clusterInstance.VtctlclientProcess.ApplySchemaWithOutput(keyspaceName, alterStatement, cluster.VtctlClientParams{DDLStrategy: ddlStrategy})
		assert.NoError(t, err)
	}
	uuid = strings.TrimSpace(uuid)

	return uuid
}

func readMigration(t *testing.T, uuid string) sqltypes.RowNamedValues {
	rs := onlineddl.ReadMigrations(t, &vtParams, uuid)
	require.NotNil(t, rs)
	row := rs.Named().Row()
	require.NotNil(t, row)
	return row
}

func waitForMigration(t *testing.T, uuid string, timeout time.Duration) sqltypes.RowNamedValues {
	var status string
	sleepDuration := time.Second
	for timeout > 0 {
		row := readMigration(t, uuid)
		status = row["migration_status"].ToString()
		switch status {
		case string(schema.OnlineDDLStatusComplete), string(schema.OnlineDDLStatusFailed):
			// migration is complete, either successful or not
			return row
		}
		time.Sleep(sleepDuration)
		timeout = timeout - sleepDuration
	}
	require.NoError(t, fmt.Errorf("timeout in waitForMigration(%s). status is: %s", uuid, status))
	return nil
}

func getTablet() *cluster.Vttablet {
	return clusterInstance.Keyspaces[0].Shards[0].Vttablets[0]
}

func mysqlParams() *mysql.ConnParams {
	if evaluatedMysqlParams != nil {
		return evaluatedMysqlParams
	}
	evaluatedMysqlParams = &mysql.ConnParams{
		Uname:      "vt_dba",
		UnixSocket: path.Join(os.Getenv("VTDATAROOT"), fmt.Sprintf("/vt_%010d", getTablet().TabletUID), "/mysql.sock"),
		DbName:     fmt.Sprintf("vt_%s", keyspaceName),
	}
	return evaluatedMysqlParams
}

// VtgateExecDDL executes a DDL query with given strategy
func mysqlExec(t *testing.T, sql string, expectError string) *sqltypes.Result {
	t.Helper()

	ctx := context.Background()
	conn, err := mysql.Connect(ctx, mysqlParams())
	require.Nil(t, err)
	defer conn.Close()

	qr, err := conn.ExecuteFetch(sql, 100000, true)
	if expectError == "" {
		require.NoError(t, err)
	} else {
		require.Error(t, err, "error should not be nil")
		require.Contains(t, err.Error(), expectError, "Unexpected error")
	}
	return qr
}

// mysqlClientExecFile runs a file through the mysql client
func mysqlClientExecFile(t *testing.T, testName string, fileName string) (output string) {
	t.Helper()

	bashPath, err := exec.LookPath("bash")
	require.NoError(t, err)
	mysqlPath, err := exec.LookPath("mysql")
	require.NoError(t, err)
	filePath, _ := filepath.Abs(path.Join(testDataPath, testName, fileName))
	params := mysqlParams()
	bashCommand := fmt.Sprintf(`%s -u%s --socket=%s --database=%s < %s 2> /tmp/error.log`, mysqlPath, params.Uname, params.UnixSocket, params.DbName, filePath)
	cmd, err := exec.Command(
		bashPath,
		"-c",
		bashCommand,
	).Output()

	require.NoError(t, err)
	return string(cmd)
}

// getCreateTableStatement returns the CREATE TABLE statement for a given table
func getCreateTableStatement(t *testing.T, tableName string) (statement string) {
	queryResult, err := getTablet().VttabletProcess.QueryTablet(fmt.Sprintf("show create table %s", tableName), keyspaceName, true)
	require.Nil(t, err)

	assert.Equal(t, len(queryResult.Rows), 1)
	assert.Equal(t, len(queryResult.Rows[0]), 2) // table name, create statement
	statement = queryResult.Rows[0][1].ToString()
	return statement
}
<|endoftext|>


<commit_before>package dialects

import (
	"database/sql"
	"reflect"
	"strconv"
	"strings"

	"github.com/gernest/ngorm/model"
)

// Dialect interface contains behaviors that differ across SQL database
type Dialect interface {
	// GetName get dialect's name
	GetName() string

	// SetDB set db for dialect
	SetDB(db model.SQLCommon)

	// BindVar return the placeholder for actual values in SQL statements, in many dbs it is "?", Postgres using $1
	BindVar(i int) string
	// Quote quotes field name to avoid SQL parsing exceptions by using a reserved word as a field name
	Quote(key string) string
	// DataTypeOf return data's sql type
	DataTypeOf(field *model.StructField) (string, error)

	// HasIndex check has index or not
	HasIndex(tableName string, indexName string) bool
	// HasForeignKey check has foreign key or not
	HasForeignKey(tableName string, foreignKeyName string) bool
	// RemoveIndex remove index
	RemoveIndex(tableName string, indexName string) error
	// HasTable check has table or not
	HasTable(tableName string) bool
	// HasColumn check has column or not
	HasColumn(tableName string, columnName string) bool

	// LimitAndOffsetSQL return generated SQL with Limit and Offset, as mssql has special case
	LimitAndOffsetSQL(limit, offset interface{}) string
	// SelectFromDummyTable return select values, for most dbs, `SELECT values` just works, mysql needs `SELECT value FROM DUAL`
	SelectFromDummyTable() string
	// LastInsertIdReturningSuffix most dbs support LastInsertId, but postgres needs to use `RETURNING`
	LastInsertIDReturningSuffix(tableName, columnName string) string

	// BuildForeignKeyName returns a foreign key name for the given table, field and reference
	BuildForeignKeyName(tableName, field, dest string) string

	// CurrentDatabase return current database name
	CurrentDatabase() string
}

//ParseFieldStructForDialect pases metadatab enough to be used by dialects. The values
//returned are useful for implementing the DataOf method of the Dialect
//interface.
//
// The fieldValue returned is the value of the field. The sqlType value returned
// is the value specified in the tags for by TYPE key, size is the value of the
// SIZE tag key it defaults to 255 when not set.
func ParseFieldStructForDialect(field *model.StructField) (fieldValue reflect.Value, sqlType string, size int, additionalType string) {
	// Get redirected field type
	var reflectType = field.Struct.Type
	for reflectType.Kind() == reflect.Ptr {
		reflectType = reflectType.Elem()
	}

	// Get redirected field value
	fieldValue = reflect.Indirect(reflect.New(reflectType))

	// Get scanner's real value
	var getScannerValue func(reflect.Value)
	getScannerValue = func(value reflect.Value) {
		fieldValue = value
		if _, isScanner := reflect.New(fieldValue.Type()).Interface().(sql.Scanner); isScanner && fieldValue.Kind() == reflect.Struct {
			getScannerValue(fieldValue.Field(0))
		}
	}
	getScannerValue(fieldValue)

	// Default Size
	if num, ok := field.TagSettings["SIZE"]; ok {
		size, _ = strconv.Atoi(num)
	} else {
		size = 255
	}

	// Default type from tag setting
	additionalType = field.TagSettings["NOT NULL"] + " " + field.TagSettings["UNIQUE"]
	if value, ok := field.TagSettings["DEFAULT"]; ok {
		additionalType = additionalType + " DEFAULT " + value
	}

	return fieldValue, field.TagSettings["TYPE"], size, strings.TrimSpace(additionalType)
}
<commit_msg>[dialects] Add godoc<commit_after>//Package dialects defines a uniform interface for creating custom support for
//different SQL databases.
package dialects

import (
	"database/sql"
	"reflect"
	"strconv"
	"strings"

	"github.com/gernest/ngorm/model"
)

// Dialect interface contains behaviors that differ across SQL database
type Dialect interface {
	// GetName get dialect's name
	GetName() string

	// SetDB set db for dialect
	SetDB(db model.SQLCommon)

	// BindVar return the placeholder for actual values in SQL statements, in many dbs it is "?", Postgres using $1
	BindVar(i int) string
	// Quote quotes field name to avoid SQL parsing exceptions by using a reserved word as a field name
	Quote(key string) string
	// DataTypeOf return data's sql type
	DataTypeOf(field *model.StructField) (string, error)

	// HasIndex check has index or not
	HasIndex(tableName string, indexName string) bool
	// HasForeignKey check has foreign key or not
	HasForeignKey(tableName string, foreignKeyName string) bool
	// RemoveIndex remove index
	RemoveIndex(tableName string, indexName string) error
	// HasTable check has table or not
	HasTable(tableName string) bool
	// HasColumn check has column or not
	HasColumn(tableName string, columnName string) bool

	// LimitAndOffsetSQL return generated SQL with Limit and Offset, as mssql has special case
	LimitAndOffsetSQL(limit, offset interface{}) string
	// SelectFromDummyTable return select values, for most dbs, `SELECT values` just works, mysql needs `SELECT value FROM DUAL`
	SelectFromDummyTable() string
	// LastInsertIdReturningSuffix most dbs support LastInsertId, but postgres needs to use `RETURNING`
	LastInsertIDReturningSuffix(tableName, columnName string) string

	// BuildForeignKeyName returns a foreign key name for the given table, field and reference
	BuildForeignKeyName(tableName, field, dest string) string

	// CurrentDatabase return current database name
	CurrentDatabase() string
}

//ParseFieldStructForDialect pases metadatab enough to be used by dialects. The values
//returned are useful for implementing the DataOf method of the Dialect
//interface.
//
// The fieldValue returned is the value of the field. The sqlType value returned
// is the value specified in the tags for by TYPE key, size is the value of the
// SIZE tag key it defaults to 255 when not set.
func ParseFieldStructForDialect(field *model.StructField) (fieldValue reflect.Value, sqlType string, size int, additionalType string) {
	// Get redirected field type
	var reflectType = field.Struct.Type
	for reflectType.Kind() == reflect.Ptr {
		reflectType = reflectType.Elem()
	}

	// Get redirected field value
	fieldValue = reflect.Indirect(reflect.New(reflectType))

	// Get scanner's real value
	var getScannerValue func(reflect.Value)
	getScannerValue = func(value reflect.Value) {
		fieldValue = value
		if _, isScanner := reflect.New(fieldValue.Type()).Interface().(sql.Scanner); isScanner && fieldValue.Kind() == reflect.Struct {
			getScannerValue(fieldValue.Field(0))
		}
	}
	getScannerValue(fieldValue)

	// Default Size
	if num, ok := field.TagSettings["SIZE"]; ok {
		size, _ = strconv.Atoi(num)
	} else {
		size = 255
	}

	// Default type from tag setting
	additionalType = field.TagSettings["NOT NULL"] + " " + field.TagSettings["UNIQUE"]
	if value, ok := field.TagSettings["DEFAULT"]; ok {
		additionalType = additionalType + " DEFAULT " + value
	}

	return fieldValue, field.TagSettings["TYPE"], size, strings.TrimSpace(additionalType)
}
<|endoftext|>


<commit_before>//Package dialects defines a uniform interface for creating custom support for
//different SQL databases.
package dialects

import (
	"database/sql"
	"fmt"
	"sync"

	"github.com/ngorm/ngorm/model"
)

// Dialect interface contains behaviors that differ across SQL database
type Dialect interface {
	// GetName get dialect's name
	GetName() string

	// SetDB set db for dialect
	SetDB(db model.SQLCommon)

	// BindVar return the placeholder for actual values in SQL statements, in many dbs it is "?", Postgres using $1
	BindVar(i int) string
	// Quote quotes field name to avoid SQL parsing exceptions by using a reserved word as a field name
	Quote(key string) string

	// DataTypeOf return data's sql type
	DataTypeOf(field *model.StructField) (string, error)

	// HasIndex check has index or not
	HasIndex(tableName string, indexName string) bool
	// HasForeignKey check has foreign key or not
	HasForeignKey(tableName string, foreignKeyName string) bool
	// RemoveIndex remove index
	RemoveIndex(tableName string, indexName string) error
	// HasTable check has table or not
	HasTable(tableName string) bool
	// HasColumn check has column or not
	HasColumn(tableName string, columnName string) bool

	// LimitAndOffsetSQL return generated SQL with Limit and Offset, as mssql has special case
	LimitAndOffsetSQL(limit, offset interface{}) string
	// SelectFromDummyTable return select values, for most dbs, `SELECT values` just works, mysql needs `SELECT value FROM DUAL`
	SelectFromDummyTable() string
	// LastInsertIdReturningSuffix most dbs support LastInsertId, but postgres needs to use `RETURNING`
	LastInsertIDReturningSuffix(tableName, columnName string) string

	// BuildForeignKeyName returns a foreign key name for the given table, field and reference
	BuildForeignKeyName(tableName, field, dest string) string

	// CurrentDatabase return current database name
	CurrentDatabase() string

	PrimaryKey([]string) string

	QueryFieldName(string) string
}

var baseOpener *DefaultOpener

func init() {
	baseOpener = &DefaultOpener{dialects: make(map[string]Dialect)}
}

func Register(d Dialect) {
	baseOpener.RegisterDialect(d)
}

//DefaultOpener implements Opener interface.
type DefaultOpener struct {
	dialects map[string]Dialect
	mu       sync.RWMutex
}

func (d *DefaultOpener) RegisterDialect(dia Dialect) {
	d.mu.Lock()
	d.dialects[dia.GetName()] = dia
	d.mu.Unlock()
}

func (d *DefaultOpener) FindDialect(dia string) Dialect {
	d.mu.RLock()
	o := d.dialects[dia]
	d.mu.RUnlock()
	return o
}

//Open opens up database connection using the database/sql package.
func (d *DefaultOpener) Open(dialect string, args ...interface{}) (model.SQLCommon, Dialect, error) {
	var source string
	var dia Dialect
	var common model.SQLCommon
	var err error

	switch value := args[0].(type) {
	case string:
		var driver = dialect
		if len(args) == 1 {
			source = value
		} else if len(args) >= 2 {
			driver = value
			source = args[1].(string)
		}
		common, err = sql.Open(driver, source)
		if err != nil {
			return nil, nil, err
		}
	case model.SQLCommon:
		common = value
	default:
		return nil, nil, fmt.Errorf("unknown argument %v", value)
	}
	dia = d.FindDialect(dialect)
	if dia == nil {
		return nil, nil, fmt.Errorf("unsupported dialect %s", dialect)
	}
	return common, dia, nil
}

func Opener() *DefaultOpener {
	return baseOpener
}

//IsQl returns true if the dialect is ql
func IsQL(d Dialect) bool {
	return d.GetName() == "ql" || d.GetName() == "ql-mem"
}
<commit_msg>[dialects] fix linting errors<commit_after>//Package dialects defines a uniform interface for creating custom support for
//different SQL databases.
package dialects

import (
	"database/sql"
	"fmt"
	"sync"

	"github.com/ngorm/ngorm/model"
)

// Dialect interface contains behaviors that differ across SQL database
type Dialect interface {
	// GetName get dialect's name
	GetName() string

	// SetDB set db for dialect
	SetDB(db model.SQLCommon)

	// BindVar return the placeholder for actual values in SQL statements, in many dbs it is "?", Postgres using $1
	BindVar(i int) string
	// Quote quotes field name to avoid SQL parsing exceptions by using a reserved word as a field name
	Quote(key string) string

	// DataTypeOf return data's sql type
	DataTypeOf(field *model.StructField) (string, error)

	// HasIndex check has index or not
	HasIndex(tableName string, indexName string) bool
	// HasForeignKey check has foreign key or not
	HasForeignKey(tableName string, foreignKeyName string) bool
	// RemoveIndex remove index
	RemoveIndex(tableName string, indexName string) error
	// HasTable check has table or not
	HasTable(tableName string) bool
	// HasColumn check has column or not
	HasColumn(tableName string, columnName string) bool

	// LimitAndOffsetSQL return generated SQL with Limit and Offset, as mssql has special case
	LimitAndOffsetSQL(limit, offset interface{}) string
	// SelectFromDummyTable return select values, for most dbs, `SELECT values` just works, mysql needs `SELECT value FROM DUAL`
	SelectFromDummyTable() string
	// LastInsertIdReturningSuffix most dbs support LastInsertId, but postgres needs to use `RETURNING`
	LastInsertIDReturningSuffix(tableName, columnName string) string

	// BuildForeignKeyName returns a foreign key name for the given table, field and reference
	BuildForeignKeyName(tableName, field, dest string) string

	// CurrentDatabase return current database name
	CurrentDatabase() string

	PrimaryKey([]string) string

	QueryFieldName(string) string
}

var baseOpener *DefaultOpener

func init() {
	baseOpener = &DefaultOpener{dialects: make(map[string]Dialect)}
}

// Register adds the dialect to global dialects registry
func Register(d Dialect) {
	baseOpener.RegisterDialect(d)
}

//DefaultOpener implements Opener interface.
type DefaultOpener struct {
	dialects map[string]Dialect
	mu       sync.RWMutex
}

// RegisterDialect stores the dialect. This is safe to call in multiple goroutines
func (d *DefaultOpener) RegisterDialect(dia Dialect) {
	d.mu.Lock()
	d.dialects[dia.GetName()] = dia
	d.mu.Unlock()
}

// FindDialect lookup for a dialect with name dia. Returns a dialect or nil in
// case there was no dialect found
func (d *DefaultOpener) FindDialect(dia string) Dialect {
	d.mu.RLock()
	o := d.dialects[dia]
	d.mu.RUnlock()
	return o
}

//Open opens up database connection using the database/sql package.
func (d *DefaultOpener) Open(dialect string, args ...interface{}) (model.SQLCommon, Dialect, error) {
	var source string
	var dia Dialect
	var common model.SQLCommon
	var err error

	switch value := args[0].(type) {
	case string:
		var driver = dialect
		if len(args) == 1 {
			source = value
		} else if len(args) >= 2 {
			driver = value
			source = args[1].(string)
		}
		common, err = sql.Open(driver, source)
		if err != nil {
			return nil, nil, err
		}
	case model.SQLCommon:
		common = value
	default:
		return nil, nil, fmt.Errorf("unknown argument %v", value)
	}
	dia = d.FindDialect(dialect)
	if dia == nil {
		return nil, nil, fmt.Errorf("unsupported dialect %s", dialect)
	}
	return common, dia, nil
}

// Opener returns the default Opener
func Opener() *DefaultOpener {
	return baseOpener
}

//IsQL returns true if the dialect is ql
func IsQL(d Dialect) bool {
	return d.GetName() == "ql" || d.GetName() == "ql-mem"
}
<|endoftext|>


<commit_before>package calendar

import (
	"time"
)

// these change every year
var (
	Day_SchoolStart, _    = time.Parse("2006-01-02", "2018-09-12")
	Day_Candlelighting, _ = time.Parse("2006-01-02", "2018-12-21")
	Day_ExamRelief, _     = time.Parse("2006-01-02", "2019-01-25")
	Day_SchoolEnd, _      = time.Parse("2006-01-02", "2019-06-06")

	SpecialSchedule_HS_Candlelighting = []SpecialScheduleItem{
		SpecialScheduleItem{"C", "", 29400, 31500},
		SpecialScheduleItem{"D", "", 31800, 33900},
		SpecialScheduleItem{"H", "", 34200, 36300},
		SpecialScheduleItem{"G", "", 36600, 38700},
		SpecialScheduleItem{"", "Long House", 39000, 41100},
		SpecialScheduleItem{"", "Candlelighting ceremony", 41400, 43200},
	}

	// import ranges
	// these should be ranges with 4 fridays in a row and the first week having no off days
	Term1_Import_Start = time.Date(2018, time.September, 24, 0, 0, 0, 0, time.UTC)
	Term1_Import_End   = time.Date(2018, time.October, 20, 0, 0, 0, 0, time.UTC)

	Term1_Import_DayOffset_Friday1 = ((7 * 2) + 4)
	Term1_Import_DayOffset_Friday2 = ((7 * 3) + 4)
	Term1_Import_DayOffset_Friday3 = 4
	Term1_Import_DayOffset_Friday4 = ((7 * 1) + 4)

	Term2_Import_Start = time.Date(2019, time.January, 28, 0, 0, 0, 0, time.UTC)
	Term2_Import_End   = time.Date(2019, time.February, 23, 0, 0, 0, 0, time.UTC)

	Term2_Import_DayOffset_Friday1 = ((7 * 3) + 4)
	Term2_Import_DayOffset_Friday2 = 4
	Term2_Import_DayOffset_Friday3 = ((7 * 1) + 4)
	Term2_Import_DayOffset_Friday4 = ((7 * 2) + 4)

	// HACK: hard-coded friday list because we can't get the fridays from the schedule because some MS teacher schedules don't have the numbers for some reason
	ScheduleFridayList = map[string]int{
		"2018-09-14": 1,
		"2018-09-21": 2,
		"2018-09-28": 3,
		"2018-10-05": 4,
		"2018-10-12": 1,
		"2018-10-19": 2,
		"2018-10-26": 3,
		"2018-11-02": 4,
		"2018-11-09": 1,
		"2018-11-16": 2,
		"2018-11-30": 3,
		"2018-12-07": 4,
		"2018-12-14": 1,
		"2019-01-11": 3,
		"2019-01-18": 4,
		"2019-01-25": 1,
		"2019-02-01": 2,
		"2019-02-08": 3,
		"2019-02-15": 4,
		"2019-02-22": 1,
		"2019-03-01": 2,
		"2019-03-08": 3,
		"2019-03-15": 4,
		"2019-04-05": 1,
		"2019-04-12": 2,
		"2019-04-26": 3,
		"2019-05-03": 4,
		"2019-05-10": 1,
		"2019-05-17": 2,
		"2019-05-24": 3,
		"2019-05-31": 4,
	}

	AssemblyTypeList = map[string]AssemblyType{
		"2018-09-13": AssemblyType_Assembly,
		"2018-09-20": AssemblyType_Assembly,
		"2018-09-27": AssemblyType_LongHouse,
		"2018-10-04": AssemblyType_Assembly,
		"2018-10-11": AssemblyType_Lab,
		"2018-10-18": AssemblyType_Assembly,
		"2018-10-25": AssemblyType_LongHouse,
		"2018-11-01": AssemblyType_Assembly,
		"2018-11-08": AssemblyType_Lab,
		"2018-11-15": AssemblyType_Assembly,
		"2018-11-29": AssemblyType_Lab,
		"2018-12-06": AssemblyType_Assembly,
		"2018-12-13": AssemblyType_LongHouse,
		"2018-12-20": AssemblyType_Assembly,
		"2019-01-10": AssemblyType_Lab,
		"2019-01-31": AssemblyType_Assembly,
		"2019-02-07": AssemblyType_Lab,
		"2019-02-14": AssemblyType_Assembly,
		"2019-02-21": AssemblyType_LongHouse,
		"2019-02-28": AssemblyType_Assembly,
		"2019-03-07": AssemblyType_Lab,
		"2019-03-14": AssemblyType_Assembly,
		"2019-04-04": AssemblyType_Lab,
		"2019-04-11": AssemblyType_Assembly,
		"2019-04-18": AssemblyType_Assembly,
		"2019-04-25": AssemblyType_LongHouse,
		"2019-05-02": AssemblyType_Assembly,
		"2019-05-09": AssemblyType_Lab,
		"2019-05-16": AssemblyType_Assembly,
		"2019-05-23": AssemblyType_Assembly,
	}

	SpecialAssessmentList = map[int]*SpecialAssessmentInfo{}
	SpecialAssessmentDays = map[string]SpecialAssessmentType{}
)

const (
	AnnouncementType_Text       = 0 // just informative
	AnnouncementType_FullOff    = 1 // no classes at all
	AnnouncementType_BreakStart = 2 // start of a break (inclusive of that day!)
	AnnouncementType_BreakEnd   = 3 // end of a break (exclusive of that day!)
)

const (
	SpecialAssessmentType_Unknown  SpecialAssessmentType = 0
	SpecialAssessmentType_English                        = 1
	SpecialAssessmentType_History                        = 2
	SpecialAssessmentType_Math                           = 3
	SpecialAssessmentType_Science                        = 4
	SpecialAssessmentType_Language                       = 5
)

// An AssemblyType describes what happens for assembly on a given week.
type AssemblyType int

const (
	AssemblyType_Assembly AssemblyType = iota
	AssemblyType_LongHouse
	AssemblyType_Lab
)

func InitCalendar() {
	// special assessments
	// no special assessments at this time
}
<commit_msg>add changes to assembly schedule<commit_after>package calendar

import (
	"time"
)

// these change every year
var (
	Day_SchoolStart, _    = time.Parse("2006-01-02", "2018-09-12")
	Day_Candlelighting, _ = time.Parse("2006-01-02", "2018-12-21")
	Day_ExamRelief, _     = time.Parse("2006-01-02", "2019-01-25")
	Day_SchoolEnd, _      = time.Parse("2006-01-02", "2019-06-06")

	SpecialSchedule_HS_Candlelighting = []SpecialScheduleItem{
		SpecialScheduleItem{"C", "", 29400, 31500},
		SpecialScheduleItem{"D", "", 31800, 33900},
		SpecialScheduleItem{"H", "", 34200, 36300},
		SpecialScheduleItem{"G", "", 36600, 38700},
		SpecialScheduleItem{"", "Long House", 39000, 41100},
		SpecialScheduleItem{"", "Candlelighting ceremony", 41400, 43200},
	}

	// import ranges
	// these should be ranges with 4 fridays in a row and the first week having no off days
	Term1_Import_Start = time.Date(2018, time.September, 24, 0, 0, 0, 0, time.UTC)
	Term1_Import_End   = time.Date(2018, time.October, 20, 0, 0, 0, 0, time.UTC)

	Term1_Import_DayOffset_Friday1 = ((7 * 2) + 4)
	Term1_Import_DayOffset_Friday2 = ((7 * 3) + 4)
	Term1_Import_DayOffset_Friday3 = 4
	Term1_Import_DayOffset_Friday4 = ((7 * 1) + 4)

	Term2_Import_Start = time.Date(2019, time.January, 28, 0, 0, 0, 0, time.UTC)
	Term2_Import_End   = time.Date(2019, time.February, 23, 0, 0, 0, 0, time.UTC)

	Term2_Import_DayOffset_Friday1 = ((7 * 3) + 4)
	Term2_Import_DayOffset_Friday2 = 4
	Term2_Import_DayOffset_Friday3 = ((7 * 1) + 4)
	Term2_Import_DayOffset_Friday4 = ((7 * 2) + 4)

	// HACK: hard-coded friday list because we can't get the fridays from the schedule because some MS teacher schedules don't have the numbers for some reason
	ScheduleFridayList = map[string]int{
		"2018-09-14": 1,
		"2018-09-21": 2,
		"2018-09-28": 3,
		"2018-10-05": 4,
		"2018-10-12": 1,
		"2018-10-19": 2,
		"2018-10-26": 3,
		"2018-11-02": 4,
		"2018-11-09": 1,
		"2018-11-16": 2,
		"2018-11-30": 3,
		"2018-12-07": 4,
		"2018-12-14": 1,
		"2019-01-11": 3,
		"2019-01-18": 4,
		"2019-01-25": 1,
		"2019-02-01": 2,
		"2019-02-08": 3,
		"2019-02-15": 4,
		"2019-02-22": 1,
		"2019-03-01": 2,
		"2019-03-08": 3,
		"2019-03-15": 4,
		"2019-04-05": 1,
		"2019-04-12": 2,
		"2019-04-26": 3,
		"2019-05-03": 4,
		"2019-05-10": 1,
		"2019-05-17": 2,
		"2019-05-24": 3,
		"2019-05-31": 4,
	}

	AssemblyTypeList = map[string]AssemblyType{
		"2018-09-13": AssemblyType_Assembly,
		"2018-09-20": AssemblyType_Assembly,
		"2018-09-27": AssemblyType_LongHouse,
		"2018-10-04": AssemblyType_Assembly,
		"2018-10-11": AssemblyType_Lab,
		"2018-10-18": AssemblyType_Assembly,
		"2018-10-25": AssemblyType_LongHouse,
		"2018-11-01": AssemblyType_Assembly,
		"2018-11-08": AssemblyType_Lab,
		"2018-11-15": AssemblyType_Assembly,
		"2018-11-29": AssemblyType_Lab,
		"2018-12-06": AssemblyType_Assembly,
		"2018-12-13": AssemblyType_LongHouse,
		"2018-12-20": AssemblyType_Assembly,
		"2019-01-10": AssemblyType_Lab,
		"2019-01-31": AssemblyType_Assembly,
		"2019-02-07": AssemblyType_Lab,
		"2019-02-14": AssemblyType_Assembly,
		"2019-02-21": AssemblyType_Lab,
		"2019-02-28": AssemblyType_Assembly,
		"2019-03-07": AssemblyType_Assembly,
		"2019-03-14": AssemblyType_Assembly,
		"2019-04-04": AssemblyType_Lab,
		"2019-04-11": AssemblyType_Assembly,
		"2019-04-18": AssemblyType_Assembly,
		"2019-04-25": AssemblyType_LongHouse,
		"2019-05-02": AssemblyType_Assembly,
		"2019-05-09": AssemblyType_Lab,
		"2019-05-16": AssemblyType_Assembly,
		"2019-05-23": AssemblyType_Assembly,
	}

	SpecialAssessmentList = map[int]*SpecialAssessmentInfo{}
	SpecialAssessmentDays = map[string]SpecialAssessmentType{}
)

const (
	AnnouncementType_Text       = 0 // just informative
	AnnouncementType_FullOff    = 1 // no classes at all
	AnnouncementType_BreakStart = 2 // start of a break (inclusive of that day!)
	AnnouncementType_BreakEnd   = 3 // end of a break (exclusive of that day!)
)

const (
	SpecialAssessmentType_Unknown  SpecialAssessmentType = 0
	SpecialAssessmentType_English                        = 1
	SpecialAssessmentType_History                        = 2
	SpecialAssessmentType_Math                           = 3
	SpecialAssessmentType_Science                        = 4
	SpecialAssessmentType_Language                       = 5
)

// An AssemblyType describes what happens for assembly on a given week.
type AssemblyType int

const (
	AssemblyType_Assembly AssemblyType = iota
	AssemblyType_LongHouse
	AssemblyType_Lab
)

func InitCalendar() {
	// special assessments
	// no special assessments at this time
}
<|endoftext|>


<commit_before>/**
 * Copyright 2017 IBM Corp.
 *
 * 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 database

import (
	"fmt"
	"github.com/IBM/ubiquity/utils/logs"
)

var migrations = make(map[string]interface{})

func RegisterMigration(obj interface{}) {
	defer logs.GetLogger().Trace(logs.DEBUG)()

	migrations[fmt.Sprintf("%v", obj)] = obj
}

func UnregisterAllMigrations() {
	defer logs.GetLogger().Trace(logs.DEBUG)()

	migrations = make(map[string]interface{})
}

func doMigrations(connection Connection) error {
	defer logs.GetLogger().Trace(logs.DEBUG)()

	logger := logs.GetLogger()
	for k, v := range migrations {
		logger.Info("migrating", logs.Args{{"migration", k}})
		if err := connection.GetDb().AutoMigrate(v).Error; err != nil {
			logger.ErrorRet(err, "failed")
		}
		delete(migrations, k)
	}
	return nil
}
<commit_msg>UB-1757 Fix for error: concurrent map writes #285<commit_after>/**
 * Copyright 2017 IBM Corp.
 *
 * 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 database

import (
	"fmt"
	"sync"
	"github.com/IBM/ubiquity/utils/logs"
)

var migrations = new(sync.Map)

func RegisterMigration(obj interface{}) {
	defer logs.GetLogger().Trace(logs.DEBUG)()
	migrations.Store(fmt.Sprintf("%v", obj), obj)
}

func UnregisterAllMigrations() {
	defer logs.GetLogger().Trace(logs.DEBUG)()
	migrations = new(sync.Map)
}

func doMigrations(connection Connection) error {
	defer logs.GetLogger().Trace(logs.DEBUG)()

	logger := logs.GetLogger()

	migrations.Range(func(k, v interface{}) bool {
		logger.Info("migrating", logs.Args{{"migration", k}})
		if err := connection.GetDb().AutoMigrate(v).Error; err != nil {
			logger.ErrorRet(err, "failed")
		}
		migrations.Delete(k)
		return true
	})

	return nil
}
<|endoftext|>


<commit_before>package option

import (
	"net/http"
	"time"

	"github.com/itchio/httpkit/timeout"
)

type EOSSettings struct {
	HTTPClient *http.Client
}

func DefaultSettings() *EOSSettings {
	return &EOSSettings{
		HTTPClient: defaultHTTPClient(),
	}
}

func defaultHTTPClient() *http.Client {
	client := timeout.NewClient(time.Second*time.Duration(30), time.Second*time.Duration(15))
	return client
}

//////////////////////////////////////

type Option interface {
	Apply(*EOSSettings)
}
<commit_msg>In default eos client, forward http headers<commit_after>package option

import (
	"errors"
	"net/http"
	"time"

	"github.com/itchio/httpkit/timeout"
)

type EOSSettings struct {
	HTTPClient *http.Client
}

func DefaultSettings() *EOSSettings {
	return &EOSSettings{
		HTTPClient: defaultHTTPClient(),
	}
}

func defaultHTTPClient() *http.Client {
	client := timeout.NewClient(time.Second*time.Duration(30), time.Second*time.Duration(15))
	client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
		if len(via) >= 10 {
			return errors.New("stopped after 10 redirects")
		}

		// forward initial request headers
		// see https://github.com/itchio/itch/issues/965
		ireq := via[0]
		for key, values := range ireq.Header {
			for _, value := range values {
				req.Header.Add(key, value)
			}
		}

		return nil
	}
	return client
}

//////////////////////////////////////

type Option interface {
	Apply(*EOSSettings)
}
<|endoftext|>


<commit_before>package main

import (
	"golang.org/x/sync/errgroup"
	"net/http"
	"time"
	"log"
	"fmt"
	"sync"
	"io/ioutil"
	"strings"
)

type transport struct {
	count int
	sync.Mutex
}

func (t *transport) RoundTrip(r *http.Request) (*http.Response, error) {
	t.Lock()
	t.count++
	t.Unlock()

	code := http.StatusOK
	status := "200 OK"
	if t.count % 3 == 0 {
		code = http.StatusInternalServerError
		status = fmt.Sprintf("500 error: count=%v", t.count)
	}
	resp := &http.Response{
		Header:     make(http.Header),
		Request:    r,
		StatusCode: code,
		Status:     status,
		Body: ioutil.NopCloser(strings.NewReader("hoge")),
	}
	resp.Header.Set("Content-Type", "text/html; charset=UTF-8")

	return resp, nil
}

var client *http.Client

func main() {
	client = &http.Client{
		Timeout: 5 * time.Second,
		Transport: &transport{},
	}
	urls := []string{
		"http://eikaiwa.dmm.com/teacher/index/6210/",
		"http://eikaiwa.dmm.com/teacher/index/5654/",
		"http://eikaiwa.dmm.com/teacher/index/5616/",
		"http://eikaiwa.dmm.com/teacher/index/3923/",
		"http://eikaiwa.dmm.com/teacher/index/5412/",
		"http://eikaiwa.dmm.com/teacher/index/9848/",
		"http://eikaiwa.dmm.com/teacher/index/6122/",
		"http://eikaiwa.dmm.com/teacher/index/3370/",
		"http://eikaiwa.dmm.com/teacher/index/13786/",
		"http://eikaiwa.dmm.com/teacher/index/3133/",
	}
	eg := errgroup.Group{}
	for _, url := range urls {
		url := url
		eg.Go(func() error {
			return getRequest(url)
		})
	}

	if err := eg.Wait(); err != nil {
		log.Fatal(err)
	}
}

func getRequest(url string) error {
	resp, err := client.Get(url)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("statusCode:%v, status:%v", resp.StatusCode, resp.Status)
	}
	_, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}
	fmt.Printf("GET: %v\n", url)
	return nil
}<commit_msg>goimports<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"strings"
	"sync"
	"time"

	"golang.org/x/sync/errgroup"
)

type transport struct {
	count int
	sync.Mutex
}

func (t *transport) RoundTrip(r *http.Request) (*http.Response, error) {
	t.Lock()
	t.count++
	t.Unlock()

	code := http.StatusOK
	status := "200 OK"
	if t.count%3 == 0 {
		code = http.StatusInternalServerError
		status = fmt.Sprintf("500 error: count=%v", t.count)
	}
	resp := &http.Response{
		Header:     make(http.Header),
		Request:    r,
		StatusCode: code,
		Status:     status,
		Body:       ioutil.NopCloser(strings.NewReader("hoge")),
	}
	resp.Header.Set("Content-Type", "text/html; charset=UTF-8")

	return resp, nil
}

var client *http.Client

func main() {
	client = &http.Client{
		Timeout:   5 * time.Second,
		Transport: &transport{},
	}
	urls := []string{
		"https://eikaiwa.dmm.com/teacher/index/6210/",
		"https://eikaiwa.dmm.com/teacher/index/5654/",
		"https://eikaiwa.dmm.com/teacher/index/5616/",
		"https://eikaiwa.dmm.com/teacher/index/3923/",
		"https://eikaiwa.dmm.com/teacher/index/5412/",
		"https://eikaiwa.dmm.com/teacher/index/9848/",
		"https://eikaiwa.dmm.com/teacher/index/6122/",
		"https://eikaiwa.dmm.com/teacher/index/3370/",
		"https://eikaiwa.dmm.com/teacher/index/13786/",
		"https://eikaiwa.dmm.com/teacher/index/3133/",
	}
	eg := errgroup.Group{}
	for _, url := range urls {
		url := url
		eg.Go(func() error {
			return getRequest(url)
		})
	}

	if err := eg.Wait(); err != nil {
		log.Fatal(err)
	}
}

func getRequest(url string) error {
	resp, err := client.Get(url)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("statusCode:%v, status:%v", resp.StatusCode, resp.Status)
	}
	_, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}
	fmt.Printf("GET: %v\n", url)
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
//
// 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 memdb implements an in-memory fake database for proof-of-concept
// purposes.
package memdb

import (
	"crypto/sha512"

	"github.com/google/e2e-key-server/db"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"

	"golang.org/x/net/context"

	cm "github.com/google/e2e-key-server/db/commitments"
)

const CommitmentSize = cm.Size

type MemDB struct {
	queue       chan *db.Mutation
	commitments map[[CommitmentSize]byte]cm.Commitment
}

// Create creates a storage object from an existing db connection.
func New() *MemDB {
	return &MemDB{
		queue:       make(chan *db.Mutation, 100),
		commitments: make(map[[CommitmentSize]byte]cm.Commitment),
	}
}

func (d *MemDB) QueueMutation(ctx context.Context, index, mutation []byte) error {
	d.queue <- &db.Mutation{index, mutation, make(chan error)}
	return nil
}

func (d *MemDB) Queue() <-chan *db.Mutation {
	return d.queue
}

func (d *MemDB) WriteCommitment(ctx context.Context, commitment, key, value []byte) error {
	var k [CommitmentSize]byte
	copy(k[:], commitment[:CommitmentSize])
	d.commitments[k] = cm.Commitment{key, value}
	return nil
}

func (d *MemDB) ReadCommitment(ctx context.Context, commitment []byte) (*cm.Commitment, error) {
	var k [CommitmentSize]byte
	copy(k[:], commitment[:CommitmentSize])
	c, ok := d.commitments[k]
	if !ok {
		return nil, grpc.Errorf(codes.NotFound, "Commitment %v not found", commitment)
	}
	return &c, nil
}
<commit_msg>fix memdb<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// 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 memdb implements an in-memory fake database for proof-of-concept
// purposes.
package memdb

import (
	"github.com/google/e2e-key-server/db"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"

	"golang.org/x/net/context"

	cm "github.com/google/e2e-key-server/db/commitments"
)

const CommitmentSize = cm.Size

type MemDB struct {
	queue       chan *db.Mutation
	commitments map[[CommitmentSize]byte]cm.Commitment
}

// Create creates a storage object from an existing db connection.
func New() *MemDB {
	return &MemDB{
		queue:       make(chan *db.Mutation, 100),
		commitments: make(map[[CommitmentSize]byte]cm.Commitment),
	}
}

func (d *MemDB) QueueMutation(ctx context.Context, index, mutation []byte) error {
	d.queue <- &db.Mutation{index, mutation, make(chan error)}
	return nil
}

func (d *MemDB) Queue() <-chan *db.Mutation {
	return d.queue
}

func (d *MemDB) WriteCommitment(ctx context.Context, commitment, key, value []byte) error {
	var k [CommitmentSize]byte
	copy(k[:], commitment[:CommitmentSize])
	d.commitments[k] = cm.Commitment{key, value}
	return nil
}

func (d *MemDB) ReadCommitment(ctx context.Context, commitment []byte) (*cm.Commitment, error) {
	var k [CommitmentSize]byte
	copy(k[:], commitment[:CommitmentSize])
	c, ok := d.commitments[k]
	if !ok {
		return nil, grpc.Errorf(codes.NotFound, "Commitment %v not found", commitment)
	}
	return &c, nil
}
<|endoftext|>


<commit_before>package mappers_test

import (
	"testing"

	"github.com/apoydence/loggrebutterfly/analyst/internal/algorithms/mappers"
	loggregator "github.com/apoydence/loggrebutterfly/api/loggregator/v2"
	v1 "github.com/apoydence/loggrebutterfly/api/v1"
	"github.com/apoydence/onpar"
	. "github.com/apoydence/onpar/expect"
	. "github.com/apoydence/onpar/matchers"
)

type TF struct {
	*testing.T
	tr mappers.Filter
}

func TestFilter(t *testing.T) {
	t.Parallel()
	o := onpar.New()
	defer o.Run(t)

	o.Group("timerange", func() {
		o.BeforeEach(func(t *testing.T) TF {
			req := &v1.QueryInfo{
				Filter: &v1.AnalystFilter{
					SourceId: "some-id",
					TimeRange: &v1.TimeRange{
						Start: 99,
						End:   101,
					},
				},
			}

			f, err := mappers.NewFilter(&v1.AggregateInfo{Query: req})
			Expect(t, err == nil).To(BeTrue())

			return TF{
				T:  t,
				tr: f,
			}
		})

		o.Spec("it only returns envelopes that have the correct source ID", func(t TF) {
			e1 := &loggregator.Envelope{SourceId: "wrong"}
			e2 := &loggregator.Envelope{SourceId: "some-id", Timestamp: 99}

			keep := t.tr.Filter(e1)
			Expect(t, keep).To(BeFalse())

			keep = t.tr.Filter(e2)
			Expect(t, keep).To(BeTrue())
		})

		o.Spec("it filters out envelopes that are outside the time range", func(t TF) {
			e1 := &loggregator.Envelope{SourceId: "some-id", Timestamp: 98}
			e2 := &loggregator.Envelope{SourceId: "some-id", Timestamp: 99}
			e3 := &loggregator.Envelope{SourceId: "some-id", Timestamp: 100}
			e4 := &loggregator.Envelope{SourceId: "some-id", Timestamp: 101}

			keep := t.tr.Filter(e1)
			Expect(t, keep).To(BeFalse())

			keep = t.tr.Filter(e2)
			Expect(t, keep).To(BeTrue())

			keep = t.tr.Filter(e3)
			Expect(t, keep).To(BeTrue())

			keep = t.tr.Filter(e4)
			Expect(t, keep).To(BeFalse())
		})
	})

	o.Group("LogFilter", func() {
		o.Group("Match", func() {
			o.BeforeEach(func(t *testing.T) TF {
				req := &v1.QueryInfo{
					Filter: &v1.AnalystFilter{
						SourceId: "some-id",
						Envelopes: &v1.AnalystFilter_Log{
							Log: &v1.LogFilter{
								Payload: &v1.LogFilter_Match{
									Match: []byte("some-value"),
								},
							},
						},
					},
				}

				f, err := mappers.NewFilter(&v1.AggregateInfo{Query: req})
				Expect(t, err == nil).To(BeTrue())

				return TF{
					T:  t,
					tr: f,
				}
			})

			o.Spec("it filters out envelopes that are not logs", func(t TF) {
				e1 := &loggregator.Envelope{
					SourceId:  "some-id",
					Timestamp: 98,
					Message: &loggregator.Envelope_Counter{
						Counter: &loggregator.Counter{
							Name: "some-name",
						},
					},
				}

				e2 := &loggregator.Envelope{
					SourceId:  "some-id",
					Timestamp: 98,
					Message: &loggregator.Envelope_Log{
						Log: &loggregator.Log{
							Payload: []byte("some-value"),
						},
					},
				}

				keep := t.tr.Filter(e1)
				Expect(t, keep).To(BeFalse())

				keep = t.tr.Filter(e2)
				Expect(t, keep).To(BeTrue())
			})

			o.Spec("it filters out envelopes that don't have the exact payload", func(t TF) {
				e1 := &loggregator.Envelope{
					SourceId:  "some-id",
					Timestamp: 98,
					Message: &loggregator.Envelope_Log{
						Log: &loggregator.Log{
							Payload: []byte("wrong-value"),
						},
					},
				}

				e2 := &loggregator.Envelope{
					SourceId:  "some-id",
					Timestamp: 98,
					Message: &loggregator.Envelope_Log{
						Log: &loggregator.Log{
							Payload: []byte("some-value"),
						},
					},
				}

				keep := t.tr.Filter(e1)
				Expect(t, keep).To(BeFalse())

				keep = t.tr.Filter(e2)
				Expect(t, keep).To(BeTrue())
			})
		})

		o.Group("Regexp", func() {
			o.BeforeEach(func(t *testing.T) TF {
				req := &v1.QueryInfo{
					Filter: &v1.AnalystFilter{
						SourceId: "some-id",
						Envelopes: &v1.AnalystFilter_Log{
							Log: &v1.LogFilter{
								Payload: &v1.LogFilter_Regexp{
									Regexp: "^[sS]ome-value",
								},
							},
						},
					},
				}

				f, err := mappers.NewFilter(&v1.AggregateInfo{Query: req})
				Expect(t, err == nil).To(BeTrue())

				return TF{
					T:  t,
					tr: f,
				}
			})

			o.Spec("it returns an error for an invalid regexp pattern", func(t TF) {
				req := &v1.QueryInfo{
					Filter: &v1.AnalystFilter{
						SourceId: "some-id",
						Envelopes: &v1.AnalystFilter_Log{
							Log: &v1.LogFilter{
								Payload: &v1.LogFilter_Regexp{
									Regexp: "[",
								},
							},
						},
					},
				}

				_, err := mappers.NewFilter(&v1.AggregateInfo{Query: req})
				Expect(t, err == nil).To(BeFalse())
			})

			o.Spec("it filters out envelopes that are not logs", func(t TF) {
				e1 := &loggregator.Envelope{
					SourceId:  "some-id",
					Timestamp: 98,
					Message: &loggregator.Envelope_Counter{
						Counter: &loggregator.Counter{
							Name: "some-name",
						},
					},
				}

				e2 := &loggregator.Envelope{
					SourceId:  "some-id",
					Timestamp: 98,
					Message: &loggregator.Envelope_Log{
						Log: &loggregator.Log{
							Payload: []byte("some-value"),
						},
					},
				}

				keep := t.tr.Filter(e1)
				Expect(t, keep).To(BeFalse())

				keep = t.tr.Filter(e2)
				Expect(t, keep).To(BeTrue())
			})

			o.Spec("it filters out envelopes that don't have the exact payload", func(t TF) {
				e1 := &loggregator.Envelope{
					SourceId:  "some-id",
					Timestamp: 98,
					Message: &loggregator.Envelope_Log{
						Log: &loggregator.Log{
							Payload: []byte("wrong-some-value"),
						},
					},
				}

				e2 := &loggregator.Envelope{
					SourceId:  "some-id",
					Timestamp: 98,
					Message: &loggregator.Envelope_Log{
						Log: &loggregator.Log{
							Payload: []byte("some-value-thats-good"),
						},
					},
				}

				keep := t.tr.Filter(e1)
				Expect(t, keep).To(BeFalse())

				keep = t.tr.Filter(e2)
				Expect(t, keep).To(BeTrue())
			})
		})
	})

	o.Group("CounterFilter", func() {
		o.Group("empty name", func() {
			o.BeforeEach(func(t *testing.T) TF {
				req := &v1.QueryInfo{
					Filter: &v1.AnalystFilter{
						SourceId: "some-id",
						Envelopes: &v1.AnalystFilter_Counter{
							Counter: &v1.CounterFilter{},
						},
					},
				}

				f, err := mappers.NewFilter(&v1.AggregateInfo{Query: req})
				Expect(t, err == nil).To(BeTrue())

				return TF{
					T:  t,
					tr: f,
				}
			})

			o.Spec("it filters out envelopes that are not counters", func(t TF) {
				e1 := &loggregator.Envelope{SourceId: "some-id", Timestamp: 98}
				e2 := &loggregator.Envelope{
					SourceId:  "some-id",
					Timestamp: 98,
					Message: &loggregator.Envelope_Counter{
						Counter: &loggregator.Counter{
							Name: "some-name",
						},
					},
				}

				keep := t.tr.Filter(e1)
				Expect(t, keep).To(BeFalse())

				keep = t.tr.Filter(e2)
				Expect(t, keep).To(BeTrue())
			})
		})

		o.Group("non-empty name", func() {
			o.BeforeEach(func(t *testing.T) TF {
				req := &v1.QueryInfo{
					Filter: &v1.AnalystFilter{
						SourceId: "some-id",
						Envelopes: &v1.AnalystFilter_Counter{
							Counter: &v1.CounterFilter{
								Name: "some-name",
							},
						},
					},
				}

				f, err := mappers.NewFilter(&v1.AggregateInfo{Query: req})
				Expect(t, err == nil).To(BeTrue())

				return TF{
					T:  t,
					tr: f,
				}
			})

			o.Spec("it filters out envelopes that are not the right name", func(t TF) {
				e1 := &loggregator.Envelope{
					SourceId:  "some-id",
					Timestamp: 97,
					Message: &loggregator.Envelope_Counter{
						Counter: &loggregator.Counter{
							Name: "wrong-name",
						},
					},
				}
				e2 := &loggregator.Envelope{
					SourceId:  "some-id",
					Timestamp: 98,
					Message: &loggregator.Envelope_Counter{
						Counter: &loggregator.Counter{
							Name: "some-name",
						},
					},
				}

				keep := t.tr.Filter(e1)
				Expect(t, keep).To(BeFalse())

				keep = t.tr.Filter(e2)
				Expect(t, keep).To(BeTrue())
			})
		})
	})
}
<commit_msg>Add empty log filter to analyst<commit_after>package mappers_test

import (
	"testing"

	"github.com/apoydence/loggrebutterfly/analyst/internal/algorithms/mappers"
	loggregator "github.com/apoydence/loggrebutterfly/api/loggregator/v2"
	v1 "github.com/apoydence/loggrebutterfly/api/v1"
	"github.com/apoydence/onpar"
	. "github.com/apoydence/onpar/expect"
	. "github.com/apoydence/onpar/matchers"
)

type TF struct {
	*testing.T
	tr mappers.Filter
}

func TestFilter(t *testing.T) {
	t.Parallel()
	o := onpar.New()
	defer o.Run(t)

	o.Group("timerange", func() {
		o.BeforeEach(func(t *testing.T) TF {
			req := &v1.QueryInfo{
				Filter: &v1.AnalystFilter{
					SourceId: "some-id",
					TimeRange: &v1.TimeRange{
						Start: 99,
						End:   101,
					},
				},
			}

			f, err := mappers.NewFilter(&v1.AggregateInfo{Query: req})
			Expect(t, err == nil).To(BeTrue())

			return TF{
				T:  t,
				tr: f,
			}
		})

		o.Spec("it only returns envelopes that have the correct source ID", func(t TF) {
			e1 := &loggregator.Envelope{SourceId: "wrong"}
			e2 := &loggregator.Envelope{SourceId: "some-id", Timestamp: 99}

			keep := t.tr.Filter(e1)
			Expect(t, keep).To(BeFalse())

			keep = t.tr.Filter(e2)
			Expect(t, keep).To(BeTrue())
		})

		o.Spec("it filters out envelopes that are outside the time range", func(t TF) {
			e1 := &loggregator.Envelope{SourceId: "some-id", Timestamp: 98}
			e2 := &loggregator.Envelope{SourceId: "some-id", Timestamp: 99}
			e3 := &loggregator.Envelope{SourceId: "some-id", Timestamp: 100}
			e4 := &loggregator.Envelope{SourceId: "some-id", Timestamp: 101}

			keep := t.tr.Filter(e1)
			Expect(t, keep).To(BeFalse())

			keep = t.tr.Filter(e2)
			Expect(t, keep).To(BeTrue())

			keep = t.tr.Filter(e3)
			Expect(t, keep).To(BeTrue())

			keep = t.tr.Filter(e4)
			Expect(t, keep).To(BeFalse())
		})
	})

	o.Group("LogFilter", func() {
		o.Group("Empty payload", func() {
			o.BeforeEach(func(t *testing.T) TF {
				req := &v1.QueryInfo{
					Filter: &v1.AnalystFilter{
						SourceId: "some-id",
						Envelopes: &v1.AnalystFilter_Log{
							Log: &v1.LogFilter{},
						},
						TimeRange: &v1.TimeRange{
							Start: 1,
							End:   9223372036854775807,
						},
					},
				}

				f, err := mappers.NewFilter(&v1.AggregateInfo{Query: req})
				Expect(t, err == nil).To(BeTrue())

				return TF{
					T:  t,
					tr: f,
				}
			})

			o.Spec("it filters out envelopes that are not logs", func(t TF) {
				e1 := &loggregator.Envelope{
					SourceId:  "some-id",
					Timestamp: 98,
					Message: &loggregator.Envelope_Counter{
						Counter: &loggregator.Counter{
							Name: "some-name",
						},
					},
				}

				e2 := &loggregator.Envelope{
					SourceId:  "some-id",
					Timestamp: 98,
					Message: &loggregator.Envelope_Log{
						Log: &loggregator.Log{
							Payload: []byte("some-value"),
						},
					},
				}

				keep := t.tr.Filter(e1)
				Expect(t, keep).To(BeFalse())

				keep = t.tr.Filter(e2)
				Expect(t, keep).To(BeTrue())
			})
		})

		o.Group("Match", func() {
			o.BeforeEach(func(t *testing.T) TF {
				req := &v1.QueryInfo{
					Filter: &v1.AnalystFilter{
						SourceId: "some-id",
						Envelopes: &v1.AnalystFilter_Log{
							Log: &v1.LogFilter{
								Payload: &v1.LogFilter_Match{
									Match: []byte("some-value"),
								},
							},
						},
					},
				}

				f, err := mappers.NewFilter(&v1.AggregateInfo{Query: req})
				Expect(t, err == nil).To(BeTrue())

				return TF{
					T:  t,
					tr: f,
				}
			})

			o.Spec("it filters out envelopes that are not logs", func(t TF) {
				e1 := &loggregator.Envelope{
					SourceId:  "some-id",
					Timestamp: 98,
					Message: &loggregator.Envelope_Counter{
						Counter: &loggregator.Counter{
							Name: "some-name",
						},
					},
				}

				e2 := &loggregator.Envelope{
					SourceId:  "some-id",
					Timestamp: 98,
					Message: &loggregator.Envelope_Log{
						Log: &loggregator.Log{
							Payload: []byte("some-value"),
						},
					},
				}

				keep := t.tr.Filter(e1)
				Expect(t, keep).To(BeFalse())

				keep = t.tr.Filter(e2)
				Expect(t, keep).To(BeTrue())
			})

			o.Spec("it filters out envelopes that don't have the exact payload", func(t TF) {
				e1 := &loggregator.Envelope{
					SourceId:  "some-id",
					Timestamp: 98,
					Message: &loggregator.Envelope_Log{
						Log: &loggregator.Log{
							Payload: []byte("wrong-value"),
						},
					},
				}

				e2 := &loggregator.Envelope{
					SourceId:  "some-id",
					Timestamp: 98,
					Message: &loggregator.Envelope_Log{
						Log: &loggregator.Log{
							Payload: []byte("some-value"),
						},
					},
				}

				keep := t.tr.Filter(e1)
				Expect(t, keep).To(BeFalse())

				keep = t.tr.Filter(e2)
				Expect(t, keep).To(BeTrue())
			})
		})

		o.Group("Regexp", func() {
			o.BeforeEach(func(t *testing.T) TF {
				req := &v1.QueryInfo{
					Filter: &v1.AnalystFilter{
						SourceId: "some-id",
						Envelopes: &v1.AnalystFilter_Log{
							Log: &v1.LogFilter{
								Payload: &v1.LogFilter_Regexp{
									Regexp: "^[sS]ome-value",
								},
							},
						},
					},
				}

				f, err := mappers.NewFilter(&v1.AggregateInfo{Query: req})
				Expect(t, err == nil).To(BeTrue())

				return TF{
					T:  t,
					tr: f,
				}
			})

			o.Spec("it returns an error for an invalid regexp pattern", func(t TF) {
				req := &v1.QueryInfo{
					Filter: &v1.AnalystFilter{
						SourceId: "some-id",
						Envelopes: &v1.AnalystFilter_Log{
							Log: &v1.LogFilter{
								Payload: &v1.LogFilter_Regexp{
									Regexp: "[",
								},
							},
						},
					},
				}

				_, err := mappers.NewFilter(&v1.AggregateInfo{Query: req})
				Expect(t, err == nil).To(BeFalse())
			})

			o.Spec("it filters out envelopes that are not logs", func(t TF) {
				e1 := &loggregator.Envelope{
					SourceId:  "some-id",
					Timestamp: 98,
					Message: &loggregator.Envelope_Counter{
						Counter: &loggregator.Counter{
							Name: "some-name",
						},
					},
				}

				e2 := &loggregator.Envelope{
					SourceId:  "some-id",
					Timestamp: 98,
					Message: &loggregator.Envelope_Log{
						Log: &loggregator.Log{
							Payload: []byte("some-value"),
						},
					},
				}

				keep := t.tr.Filter(e1)
				Expect(t, keep).To(BeFalse())

				keep = t.tr.Filter(e2)
				Expect(t, keep).To(BeTrue())
			})

			o.Spec("it filters out envelopes that don't have the exact payload", func(t TF) {
				e1 := &loggregator.Envelope{
					SourceId:  "some-id",
					Timestamp: 98,
					Message: &loggregator.Envelope_Log{
						Log: &loggregator.Log{
							Payload: []byte("wrong-some-value"),
						},
					},
				}

				e2 := &loggregator.Envelope{
					SourceId:  "some-id",
					Timestamp: 98,
					Message: &loggregator.Envelope_Log{
						Log: &loggregator.Log{
							Payload: []byte("some-value-thats-good"),
						},
					},
				}

				keep := t.tr.Filter(e1)
				Expect(t, keep).To(BeFalse())

				keep = t.tr.Filter(e2)
				Expect(t, keep).To(BeTrue())
			})
		})
	})

	o.Group("CounterFilter", func() {
		o.Group("empty name", func() {
			o.BeforeEach(func(t *testing.T) TF {
				req := &v1.QueryInfo{
					Filter: &v1.AnalystFilter{
						SourceId: "some-id",
						Envelopes: &v1.AnalystFilter_Counter{
							Counter: &v1.CounterFilter{},
						},
					},
				}

				f, err := mappers.NewFilter(&v1.AggregateInfo{Query: req})
				Expect(t, err == nil).To(BeTrue())

				return TF{
					T:  t,
					tr: f,
				}
			})

			o.Spec("it filters out envelopes that are not counters", func(t TF) {
				e1 := &loggregator.Envelope{SourceId: "some-id", Timestamp: 98}
				e2 := &loggregator.Envelope{
					SourceId:  "some-id",
					Timestamp: 98,
					Message: &loggregator.Envelope_Counter{
						Counter: &loggregator.Counter{
							Name: "some-name",
						},
					},
				}

				keep := t.tr.Filter(e1)
				Expect(t, keep).To(BeFalse())

				keep = t.tr.Filter(e2)
				Expect(t, keep).To(BeTrue())
			})
		})

		o.Group("non-empty name", func() {
			o.BeforeEach(func(t *testing.T) TF {
				req := &v1.QueryInfo{
					Filter: &v1.AnalystFilter{
						SourceId: "some-id",
						Envelopes: &v1.AnalystFilter_Counter{
							Counter: &v1.CounterFilter{
								Name: "some-name",
							},
						},
					},
				}

				f, err := mappers.NewFilter(&v1.AggregateInfo{Query: req})
				Expect(t, err == nil).To(BeTrue())

				return TF{
					T:  t,
					tr: f,
				}
			})

			o.Spec("it filters out envelopes that are not the right name", func(t TF) {
				e1 := &loggregator.Envelope{
					SourceId:  "some-id",
					Timestamp: 97,
					Message: &loggregator.Envelope_Counter{
						Counter: &loggregator.Counter{
							Name: "wrong-name",
						},
					},
				}
				e2 := &loggregator.Envelope{
					SourceId:  "some-id",
					Timestamp: 98,
					Message: &loggregator.Envelope_Counter{
						Counter: &loggregator.Counter{
							Name: "some-name",
						},
					},
				}

				keep := t.tr.Filter(e1)
				Expect(t, keep).To(BeFalse())

				keep = t.tr.Filter(e2)
				Expect(t, keep).To(BeTrue())
			})
		})
	})
}
<|endoftext|>