<commit_before>// Copyright 2017 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.

// [START bigquery_datatransfer_quickstart]

// Sample bigquery-quickstart creates a Google BigQuery dataset.
package main

import (
	"fmt"
	"log"

	"golang.org/x/net/context"
	"google.golang.org/api/iterator"

	// Imports the BigQuery Data Transfer client package.
	datatransfer "cloud.google.com/go/bigquery/datatransfer/apiv1"
	datatransferpb "google.golang.org/genproto/googleapis/cloud/bigquery/datatransfer/v1"
)

func main() {
	ctx := context.Background()

	// Sets your Google Cloud Platform project ID.
	projectID := "YOUR_PROJECT_ID"

	// Creates a client.
	client, err := datatransfer.NewClient(ctx)
	if err != nil {
		log.Fatalf("Failed to create client: %v", err)
	}

	req := &datatransferpb.ListDataSourcesRequest{
		Parent: fmt.Sprintf("projects/%s", projectID),
	}
	it := client.ListDataSources(ctx, req)
	fmt.Println("Supported Data Sources:")
	for {
		ds, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			log.Fatalf("Failed to list sources: %v", err)
		}
		fmt.Println(ds.DisplayName)
		fmt.Println("\tID: ", ds.DataSourceId)
		fmt.Println("\tFull path: ", ds.Name)
		fmt.Println("\tDescription: ", ds.Description)
	}
}

// [END bigquery_datatransfer_quickstart]
<commit_msg>bigquery_datatransfer -> bigquerydatatransfer<commit_after>// Copyright 2017 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.

// [START bigquerydatatransfer_quickstart]

// Sample bigquery-quickstart creates a Google BigQuery dataset.
package main

import (
	"fmt"
	"log"

	"golang.org/x/net/context"
	"google.golang.org/api/iterator"

	// Imports the BigQuery Data Transfer client package.
	datatransfer "cloud.google.com/go/bigquery/datatransfer/apiv1"
	datatransferpb "google.golang.org/genproto/googleapis/cloud/bigquery/datatransfer/v1"
)

func main() {
	ctx := context.Background()

	// Sets your Google Cloud Platform project ID.
	projectID := "YOUR_PROJECT_ID"

	// Creates a client.
	client, err := datatransfer.NewClient(ctx)
	if err != nil {
		log.Fatalf("Failed to create client: %v", err)
	}

	req := &datatransferpb.ListDataSourcesRequest{
		Parent: fmt.Sprintf("projects/%s", projectID),
	}
	it := client.ListDataSources(ctx, req)
	fmt.Println("Supported Data Sources:")
	for {
		ds, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			log.Fatalf("Failed to list sources: %v", err)
		}
		fmt.Println(ds.DisplayName)
		fmt.Println("\tID: ", ds.DataSourceId)
		fmt.Println("\tFull path: ", ds.Name)
		fmt.Println("\tDescription: ", ds.Description)
	}
}

// [END bigquerydatatransfer_quickstart]
<|endoftext|>


<commit_before>// Package main for tenet testing
package main

import (
	"fmt"
)

type Reader interface {
	Read() []byte
}

type SomeName interface {
	Read() []byte
}

type Writer interface {
	Write() int
}

type SomeWriter interface {
	Write() int
}

type DoesntCount interface {
	Write() int
	Read() []byte
}

type Read interface {
	Reader() []byte
}

func main() {
	fmt.Println("Hello, world!")
}
<commit_msg>Added interface comments to please the review bot<commit_after>// Package main for tenet testing
package main

import (
	"fmt"
)

// Reader is an example interface
type Reader interface {
	Read() []byte
}

// SomeName is an example interface
type SomeName interface {
	Read() []byte
}

// Writer is an example interface
type Writer interface {
	Write() int
}

// SomeWriter is an example interface
type SomeWriter interface {
	Write() int
}

// DoesntCount is an example interface
type DoesntCount interface {
	Write() int
	Read() []byte
}

// Read is an example interface
type Read interface {
	Reader() []byte
}

func main() {
	fmt.Println("Hello, world!")
}
<|endoftext|>


<commit_before>package otto

import (
	. "./terst"
	"fmt"
	"testing"
	Time "time"
)

func TestDate(t *testing.T) {
	Terst(t)

	test := runTest()

	time := Time.Unix(1348616313, 47*1000*1000).Local()
	check := func(run string, value int) {
		test(run, fmt.Sprintf("%d", value))
	}

	test(`Date`, "[function]")
	test(`new Date(0).toUTCString()`, "Thu, 01 Jan 1970 00:00:00 UTC")
	test(`new Date(0).toGMTString()`, "Thu, 01 Jan 1970 00:00:00 GMT")
	if false {
		// TODO
		test(`new Date(0).toLocaleString()`, "")
		test(`new Date(0).toLocaleDateString()`, "")
		test(`new Date(0).toLocaleTimeString()`, "")
	}
	test(`new Date(1348616313).getTime()`, "1348616313")
	test(`new Date(1348616313).toUTCString()`, "Fri, 16 Jan 1970 14:36:56 UTC")
	test(`abc = new Date(1348616313047); abc.toUTCString()`, "Tue, 25 Sep 2012 23:38:33 UTC")
	check(`abc.getYear()`, time.Year()-1900)
	check(`abc.getFullYear()`, time.Year())
	check(`abc.getUTCFullYear()`, 2012)
	check(`abc.getMonth()`, int(time.Month())-1) // Remember, the JavaScript month is 0-based
	check(`abc.getUTCMonth()`, 8)
	check(`abc.getDate()`, time.Day())
	check(`abc.getUTCDate()`, 25)
	check(`abc.getDay()`, int(time.Weekday()))
	check(`abc.getUTCDay()`, 2)
	check(`abc.getHours()`, time.Hour())
	check(`abc.getUTCHours()`, 23)
	check(`abc.getMinutes()`, time.Minute())
	check(`abc.getUTCMinutes()`, 38)
	check(`abc.getSeconds()`, time.Second())
	check(`abc.getUTCSeconds()`, 33)
	check(`abc.getMilliseconds()`, time.Nanosecond()/(1000*1000)) // In honor of the 47%
	check(`abc.getUTCMilliseconds()`, 47)
	_, offset := time.Zone()
	check(`abc.getTimezoneOffset()`, offset/-60)
	if false {
		// TODO (When parsing is implemented)
		test(`new Date("Xyzzy").getTime()`, "NaN")
	}

	test(`abc.setFullYear(2011); abc.toUTCString()`, "Sun, 25 Sep 2011 23:38:33 UTC")
	test(`new Date(12564504e5).toUTCString()`, "Sun, 25 Oct 2009 06:00:00 UTC")
	test(`new Date(2009, 9, 25).toUTCString()`, "Sun, 25 Oct 2009 00:00:00 UTC")
	test(`+(new Date(2009, 9, 25))`, "1256428800000")

	format := "Mon, 2 Jan 2006 15:04:05 MST"

	tme := Time.Unix(1256450400, 0)
	time = Time.Date(tme.Year(), tme.Month(), tme.Day(), tme.Hour(), tme.Minute(), tme.Second(), tme.Nanosecond(), tme.Location()).UTC()

	time = Time.Date(tme.Year(), tme.Month(), tme.Day(), tme.Hour(), tme.Minute(), tme.Second(), 2001*1000*1000, tme.Location()).UTC()
	test(`abc = new Date(12564504e5); abc.setMilliseconds(2001); abc.toUTCString()`, time.Format(format))

	time = Time.Date(tme.Year(), tme.Month(), tme.Day(), tme.Hour(), tme.Minute(), 61, tme.Nanosecond(), tme.Location()).UTC()
	test(`abc = new Date(12564504e5); abc.setSeconds("61"); abc.toUTCString()`, time.Format(format))

	time = Time.Date(tme.Year(), tme.Month(), tme.Day(), tme.Hour(), 61, tme.Second(), tme.Nanosecond(), tme.Location()).UTC()
	test(`abc = new Date(12564504e5); abc.setMinutes("61"); abc.toUTCString()`, time.Format(format))

	time = Time.Date(tme.Year(), tme.Month(), tme.Day(), 5, tme.Minute(), tme.Second(), tme.Nanosecond(), tme.Location()).UTC()
	test(`abc = new Date(12564504e5); abc.setHours("5"); abc.toUTCString()`, time.Format(format))

	time = Time.Date(tme.Year(), tme.Month(), 26, tme.Hour(), tme.Minute(), tme.Second(), tme.Nanosecond(), tme.Location()).UTC()
	test(`abc = new Date(12564504e5); abc.setDate("26"); abc.toUTCString()`, time.Format(format))

	time = Time.Date(tme.Year(), 10, tme.Day(), tme.Hour(), tme.Minute(), tme.Second(), tme.Nanosecond(), tme.Location()).UTC()
	test(`abc = new Date(12564504e5); abc.setMonth(9); abc.toUTCString()`, time.Format(format))
	test(`abc = new Date(12564504e5); abc.setMonth("09"); abc.toUTCString()`, time.Format(format))

	time = Time.Date(tme.Year(), 11, tme.Day(), tme.Hour(), tme.Minute(), tme.Second(), tme.Nanosecond(), tme.Location()).UTC()
	test(`abc = new Date(12564504e5); abc.setMonth("10"); abc.toUTCString()`, time.Format(format))

	time = Time.Date(2010, tme.Month(), tme.Day(), tme.Hour(), tme.Minute(), tme.Second(), tme.Nanosecond(), tme.Location()).UTC()
	test(`abc = new Date(12564504e5); abc.setFullYear(2010); abc.toUTCString()`, time.Format(format))

	test(`new Date("2001-01-01T10:01:02.000").getTime()`, "978343262000")

	// Date()
	test(`typeof Date()`, "string")
	test(`typeof Date(2006, 1, 2)`, "string")
}

func TestDate_parse(t *testing.T) {
	Terst(t)

	test := runTest()
	test(`Date.parse("2001-01-01T10:01:02.000")`, "978343262000")
	test(`Date.parse("2006-01-02T15:04:05.000")`, "1136214245000")
	test(`Date.parse("2006")`, "1136073600000")
	test(`Date.parse("1970-01-16T14:36:56+00:00")`, "1348616000")
	test(`Date.parse("1970-01-16T14:36:56.313+00:00")`, "1348616313")
	test(`Date.parse("1970-01-16T14:36:56.000")`, "1348616000")
}

func TestDate_UTC(t *testing.T) {
	Terst(t)

	test := runTest()
	test(`Date.UTC(2009, 9, 25)`, "1256428800000")
}

func TestDate_setYear(t *testing.T) {
	Terst(t)

	test := runTest()
	test(`new Date(12564504e5).setYear(96)`, "846223200000")
	test(`new Date(12564504e5).setYear(1996)`, "846223200000")
	test(`new Date(12564504e5).setYear(2000)`, "972453600000")
}

func TestDateDefaultValue(t *testing.T) {
	Terst(t)

	test := runTest()
	test(`
        var date = new Date();
        date + 0 === date.toString() + "0";
    `, "true")
}
<commit_msg>Fix test to pass regardless of time zone (always UTC)<commit_after>package otto

import (
	. "./terst"
	"fmt"
	"testing"
	Time "time"
)

func TestDate(t *testing.T) {
	Terst(t)

	test := runTest()

	time := Time.Unix(1348616313, 47*1000*1000).Local()
	check := func(run string, value int) {
		test(run, fmt.Sprintf("%d", value))
	}

	test(`Date`, "[function]")
	test(`new Date(0).toUTCString()`, "Thu, 01 Jan 1970 00:00:00 UTC")
	test(`new Date(0).toGMTString()`, "Thu, 01 Jan 1970 00:00:00 GMT")
	if false {
		// TODO
		test(`new Date(0).toLocaleString()`, "")
		test(`new Date(0).toLocaleDateString()`, "")
		test(`new Date(0).toLocaleTimeString()`, "")
	}
	test(`new Date(1348616313).getTime()`, "1348616313")
	test(`new Date(1348616313).toUTCString()`, "Fri, 16 Jan 1970 14:36:56 UTC")
	test(`abc = new Date(1348616313047); abc.toUTCString()`, "Tue, 25 Sep 2012 23:38:33 UTC")
	check(`abc.getYear()`, time.Year()-1900)
	check(`abc.getFullYear()`, time.Year())
	check(`abc.getUTCFullYear()`, 2012)
	check(`abc.getMonth()`, int(time.Month())-1) // Remember, the JavaScript month is 0-based
	check(`abc.getUTCMonth()`, 8)
	check(`abc.getDate()`, time.Day())
	check(`abc.getUTCDate()`, 25)
	check(`abc.getDay()`, int(time.Weekday()))
	check(`abc.getUTCDay()`, 2)
	check(`abc.getHours()`, time.Hour())
	check(`abc.getUTCHours()`, 23)
	check(`abc.getMinutes()`, time.Minute())
	check(`abc.getUTCMinutes()`, 38)
	check(`abc.getSeconds()`, time.Second())
	check(`abc.getUTCSeconds()`, 33)
	check(`abc.getMilliseconds()`, time.Nanosecond()/(1000*1000)) // In honor of the 47%
	check(`abc.getUTCMilliseconds()`, 47)
	_, offset := time.Zone()
	check(`abc.getTimezoneOffset()`, offset/-60)
	if false {
		// TODO (When parsing is implemented)
		test(`new Date("Xyzzy").getTime()`, "NaN")
	}

	test(`abc.setFullYear(2011); abc.toUTCString()`, "Sun, 25 Sep 2011 23:38:33 UTC")
	test(`new Date(12564504e5).toUTCString()`, "Sun, 25 Oct 2009 06:00:00 UTC")
	test(`new Date(2009, 9, 25).toUTCString()`, "Sun, 25 Oct 2009 00:00:00 UTC")
	test(`+(new Date(2009, 9, 25))`, "1256428800000")

	format := "Mon, 2 Jan 2006 15:04:05 MST"

	tme := Time.Unix(1256450400, 0)
	time = Time.Date(tme.Year(), tme.Month(), tme.Day(), tme.Hour(), tme.Minute(), tme.Second(), tme.Nanosecond(), tme.Location()).UTC()

	time = Time.Date(tme.Year(), tme.Month(), tme.Day(), tme.Hour(), tme.Minute(), tme.Second(), 2001*1000*1000, tme.Location()).UTC()
	test(`abc = new Date(12564504e5); abc.setMilliseconds(2001); abc.toUTCString()`, time.Format(format))

	time = Time.Date(tme.Year(), tme.Month(), tme.Day(), tme.Hour(), tme.Minute(), 61, tme.Nanosecond(), tme.Location()).UTC()
	test(`abc = new Date(12564504e5); abc.setSeconds("61"); abc.toUTCString()`, time.Format(format))

	time = Time.Date(tme.Year(), tme.Month(), tme.Day(), tme.Hour(), 61, tme.Second(), tme.Nanosecond(), tme.Location()).UTC()
	test(`abc = new Date(12564504e5); abc.setMinutes("61"); abc.toUTCString()`, time.Format(format))

	time = Time.Date(tme.Year(), tme.Month(), tme.Day(), 5, tme.Minute(), tme.Second(), tme.Nanosecond(), tme.Location()).UTC()
	test(`abc = new Date(12564504e5); abc.setHours("5"); abc.toUTCString()`, time.Format(format))

	time = Time.Date(tme.Year(), tme.Month(), 26, tme.Hour(), tme.Minute(), tme.Second(), tme.Nanosecond(), tme.Location()).UTC()
	test(`abc = new Date(12564504e5); abc.setDate("26"); abc.toUTCString()`, time.Format(format))

	time = Time.Date(tme.Year(), 10, tme.Day(), tme.Hour(), tme.Minute(), tme.Second(), tme.Nanosecond(), tme.Location()).UTC()
	test(`abc = new Date(12564504e5); abc.setMonth(9); abc.toUTCString()`, time.Format(format))
	test(`abc = new Date(12564504e5); abc.setMonth("09"); abc.toUTCString()`, time.Format(format))

	time = Time.Date(tme.Year(), 11, tme.Day(), tme.Hour(), tme.Minute(), tme.Second(), tme.Nanosecond(), tme.Location()).UTC()
	test(`abc = new Date(12564504e5); abc.setMonth("10"); abc.toUTCString()`, time.Format(format))

	time = Time.Date(2010, tme.Month(), tme.Day(), tme.Hour(), tme.Minute(), tme.Second(), tme.Nanosecond(), tme.Location()).UTC()
	test(`abc = new Date(12564504e5); abc.setFullYear(2010); abc.toUTCString()`, time.Format(format))

	test(`new Date("2001-01-01T10:01:02.000").getTime()`, "978343262000")

	// Date()
	test(`typeof Date()`, "string")
	test(`typeof Date(2006, 1, 2)`, "string")
}

func TestDate_parse(t *testing.T) {
	Terst(t)

	test := runTest()
	test(`Date.parse("2001-01-01T10:01:02.000")`, "978343262000")
	test(`Date.parse("2006-01-02T15:04:05.000")`, "1136214245000")
	test(`Date.parse("2006")`, "1136073600000")
	test(`Date.parse("1970-01-16T14:36:56+00:00")`, "1348616000")
	test(`Date.parse("1970-01-16T14:36:56.313+00:00")`, "1348616313")
	test(`Date.parse("1970-01-16T14:36:56.000")`, "1348616000")
}

func TestDate_UTC(t *testing.T) {
	Terst(t)

	test := runTest()
	test(`Date.UTC(2009, 9, 25)`, "1256428800000")
}

func TestDate_setYear(t *testing.T) {
	Terst(t)

	// Make sure we do not fail just because we're running
	// the test in a different time zone
	local := Time.Local
	Time.Local = Time.UTC
	defer func() {
		Time.Local = local
	}()
	test := runTest()
	test(`new Date(12564504e5).setYear(96)`, "846223200000")
	test(`new Date(12564504e5).setYear(1996)`, "846223200000")
	test(`new Date(12564504e5).setYear(2000)`, "972453600000")
}

func TestDateDefaultValue(t *testing.T) {
	Terst(t)

	test := runTest()
	test(`
        var date = new Date();
        date + 0 === date.toString() + "0";
    `, "true")
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Mute Communications Ltd.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package memstore

import (
	"bytes"
	"io"
	"testing"

	"github.com/mutecomm/mute/cipher"
	"github.com/mutecomm/mute/encode/base64"
	"github.com/mutecomm/mute/keyserver/hashchain"
	"github.com/mutecomm/mute/msg"
	"github.com/mutecomm/mute/uid"
	"github.com/mutecomm/mute/util/times"
)

func TestKeyEntry(t *testing.T) {
	ms := New()
	uidMsg, err := uid.Create("alice@mute.berlin", false, "", "", uid.Strict,
		hashchain.TestEntry, cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}
	now := uint64(times.Now())
	ki, _, _, err := uidMsg.KeyInit(1, now+times.Day, now-times.Day, false,
		"mute.berlin", "", "", cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}
	ke, err := ki.KeyEntryECDHE25519(uidMsg.SigPubKey())
	if err != nil {
		t.Fatal(err)
	}
	// private
	ms.AddPrivateKeyEntry(ke)
	entry, err := ms.GetPrivateKeyEntry(ke.HASH)
	if err != nil {
		t.Error(err)
	} else if entry != ke {
		t.Error("entry != ke")
	}
	if _, err := ms.GetPrivateKeyEntry("MUTE"); err == nil {
		t.Error("should fail")
	}
	// public
	ms.AddPublicKeyEntry(uidMsg.Identity(), ke)
	entry, _, err = ms.GetPublicKeyEntry(uidMsg)
	if err != nil {
		t.Error(err)
	} else if entry != ke {
		t.Error("entry != ke")
	}
	uidMsg, err = uid.Create("trent@mute.berlin", false, "", "", uid.Strict,
		hashchain.TestEntry, cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}
	if _, _, err := ms.GetPublicKeyEntry(uidMsg); err != msg.ErrNoKeyInit {
		t.Error("should fail with msg.ErrNoKeyInit")
	}
}

func genMessageKey() (*[64]byte, error) {
	var messageKey [64]byte
	if _, err := io.ReadFull(cipher.RandReader, messageKey[:]); err != nil {
		return nil, err
	}
	return &messageKey, nil
}

func TestSessionStore(t *testing.T) {
	ms := New()
	sendKey, err := genMessageKey()
	if err != nil {
		t.Fatal(err)
	}
	recvKey, err := genMessageKey()
	if err != nil {
		t.Fatal(err)
	}
	rootKeyHash := cipher.SHA512([]byte("rootkey"))
	if ms.HasSession("alice@mute.berlin", "bob@mute.berlin", "hash") {
		t.Error("HasSession() should fail")
	}
	err = ms.StoreSession("alice@mute.berlin", "bob@mute.berlin", "hash",
		base64.Encode(rootKeyHash),
		base64.Encode(cipher.SHA512([]byte("chainkey"))),
		[]string{base64.Encode(sendKey[:])},
		[]string{base64.Encode(recvKey[:])})
	if err != nil {
		t.Fatal(err)
	}
	if !ms.HasSession("alice@mute.berlin", "bob@mute.berlin", "hash") {
		t.Error("HasSession() should succeed")
	}
	if ms.SenderSessionPubHash() != "hash" {
		t.Error("wrong SenderSessionPubHash() result")
	}
	// test root key hash
	h, err := ms.GetRootKeyHash("alice@mute.berlin", "bob@mute.berlin", "hash")
	if err != nil {
		t.Fatal(err)
	}
	if !bytes.Equal(h[:], rootKeyHash[:]) {
		t.Error("root key hashes are not equal")
	}
	// test sender key
	key, err := ms.GetMessageKey("alice@mute.berlin", "bob@mute.berlin",
		"hash", true, 0)
	if err != nil {
		t.Fatal(err)
	}
	if !bytes.Equal(key[:], sendKey[:]) {
		t.Error("send key differs")
	}
	err = ms.DelMessageKey("alice@mute.berlin", "bob@mute.berlin", "hash",
		true, 0)
	if err != nil {
		t.Fatal(err)
	}
	_, err = ms.GetMessageKey("alice@mute.berlin", "bob@mute.berlin", "hash",
		true, 0)
	if err != msg.ErrMessageKeyUsed {
		t.Error("should fail with msg.ErrMessageKeyUsed")
	}
	// test receiver key
	key, err = ms.GetMessageKey("alice@mute.berlin", "bob@mute.berlin",
		"hash", false, 0)
	if err != nil {
		t.Fatal(err)
	}
	if !bytes.Equal(key[:], recvKey[:]) {
		t.Error("recv key differs")
	}
	err = ms.DelMessageKey("alice@mute.berlin", "bob@mute.berlin", "hash",
		false, 0)
	if err != nil {

		t.Fatal(err)
	}
	_, err = ms.GetMessageKey("alice@mute.berlin", "bob@mute.berlin", "hash",
		false, 0)
	if err != msg.ErrMessageKeyUsed {
		t.Error("should fail with msg.ErrMessageKeyUsed")
	}
}

func TestSessionState(t *testing.T) {
	ms := New()
	ss := &msg.SessionState{
		SenderSessionCount:    1,
		SenderMessageCount:    2,
		RecipientSessionCount: 3,
		RecipientMessageCount: 4,
	}
	err := ms.SetSessionState("alice@mute.berlin", "bob@mute.berlin", ss)
	if err != nil {
		t.Fatal(err)
	}
	sss, err := ms.GetSessionState("alice@mute.berlin", "bob@mute.berlin")
	if err != nil {
		t.Fatal(err)
	}
	if ss != sss {
		t.Error("session states differ")
	}
}
<commit_msg>memstore: fix tests<commit_after>// Copyright (c) 2015 Mute Communications Ltd.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package memstore

import (
	"bytes"
	"io"
	"testing"

	"github.com/mutecomm/mute/cipher"
	"github.com/mutecomm/mute/encode/base64"
	"github.com/mutecomm/mute/keyserver/hashchain"
	"github.com/mutecomm/mute/msg/session"
	"github.com/mutecomm/mute/uid"
	"github.com/mutecomm/mute/util/times"
)

func TestKeyEntry(t *testing.T) {
	ms := New()
	uidMsg, err := uid.Create("alice@mute.berlin", false, "", "", uid.Strict,
		hashchain.TestEntry, cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}
	now := uint64(times.Now())
	ki, _, _, err := uidMsg.KeyInit(1, now+times.Day, now-times.Day, false,
		"mute.berlin", "", "", cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}
	ke, err := ki.KeyEntryECDHE25519(uidMsg.SigPubKey())
	if err != nil {
		t.Fatal(err)
	}
	// private
	ms.AddPrivateKeyEntry(ke)
	entry, err := ms.GetPrivateKeyEntry(ke.HASH)
	if err != nil {
		t.Error(err)
	} else if entry != ke {
		t.Error("entry != ke")
	}
	if _, err := ms.GetPrivateKeyEntry("MUTE"); err == nil {
		t.Error("should fail")
	}
	// public
	ms.AddPublicKeyEntry(uidMsg.Identity(), ke)
	entry, _, err = ms.GetPublicKeyEntry(uidMsg)
	if err != nil {
		t.Error(err)
	} else if entry != ke {
		t.Error("entry != ke")
	}
	uidMsg, err = uid.Create("trent@mute.berlin", false, "", "", uid.Strict,
		hashchain.TestEntry, cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}
	if _, _, err := ms.GetPublicKeyEntry(uidMsg); err != session.ErrNoKeyInit {
		t.Error("should fail with session.ErrNoKeyInit")
	}
}

func genMessageKey() (*[64]byte, error) {
	var messageKey [64]byte
	if _, err := io.ReadFull(cipher.RandReader, messageKey[:]); err != nil {
		return nil, err
	}
	return &messageKey, nil
}

func TestSessionStore(t *testing.T) {
	ms := New()
	sendKey, err := genMessageKey()
	if err != nil {
		t.Fatal(err)
	}
	recvKey, err := genMessageKey()
	if err != nil {
		t.Fatal(err)
	}
	rootKeyHash := cipher.SHA512([]byte("rootkey"))
	if ms.HasSession("alice@mute.berlin", "bob@mute.berlin", "hash") {
		t.Error("HasSession() should fail")
	}
	err = ms.StoreSession("alice@mute.berlin", "bob@mute.berlin", "hash",
		base64.Encode(rootKeyHash),
		base64.Encode(cipher.SHA512([]byte("chainkey"))),
		[]string{base64.Encode(sendKey[:])},
		[]string{base64.Encode(recvKey[:])})
	if err != nil {
		t.Fatal(err)
	}
	if !ms.HasSession("alice@mute.berlin", "bob@mute.berlin", "hash") {
		t.Error("HasSession() should succeed")
	}
	if ms.SenderSessionPubHash() != "hash" {
		t.Error("wrong SenderSessionPubHash() result")
	}
	// test root key hash
	h, err := ms.GetRootKeyHash("alice@mute.berlin", "bob@mute.berlin", "hash")
	if err != nil {
		t.Fatal(err)
	}
	if !bytes.Equal(h[:], rootKeyHash[:]) {
		t.Error("root key hashes are not equal")
	}
	// test sender key
	key, err := ms.GetMessageKey("alice@mute.berlin", "bob@mute.berlin",
		"hash", true, 0)
	if err != nil {
		t.Fatal(err)
	}
	if !bytes.Equal(key[:], sendKey[:]) {
		t.Error("send key differs")
	}
	err = ms.DelMessageKey("alice@mute.berlin", "bob@mute.berlin", "hash",
		true, 0)
	if err != nil {
		t.Fatal(err)
	}
	_, err = ms.GetMessageKey("alice@mute.berlin", "bob@mute.berlin", "hash",
		true, 0)
	if err != session.ErrMessageKeyUsed {
		t.Error("should fail with session.ErrMessageKeyUsed")
	}
	// test receiver key
	key, err = ms.GetMessageKey("alice@mute.berlin", "bob@mute.berlin",
		"hash", false, 0)
	if err != nil {
		t.Fatal(err)
	}
	if !bytes.Equal(key[:], recvKey[:]) {
		t.Error("recv key differs")
	}
	err = ms.DelMessageKey("alice@mute.berlin", "bob@mute.berlin", "hash",
		false, 0)
	if err != nil {

		t.Fatal(err)
	}
	_, err = ms.GetMessageKey("alice@mute.berlin", "bob@mute.berlin", "hash",
		false, 0)
	if err != session.ErrMessageKeyUsed {
		t.Error("should fail with session.ErrMessageKeyUsed")
	}
}

func TestSessionState(t *testing.T) {
	ms := New()
	ss := &session.State{
		SenderSessionCount:    1,
		SenderMessageCount:    2,
		RecipientSessionCount: 3,
		RecipientMessageCount: 4,
	}
	err := ms.SetSessionState("alice@mute.berlin", "bob@mute.berlin", ss)
	if err != nil {
		t.Fatal(err)
	}
	sss, err := ms.GetSessionState("alice@mute.berlin", "bob@mute.berlin")
	if err != nil {
		t.Fatal(err)
	}
	if ss != sss {
		t.Error("session states differ")
	}
}
<|endoftext|>


<commit_before>package protocol

import (
	"fmt"
)

// A PacketNumber in QUIC
type PacketNumber uint64

// PacketNumberLen is the length of the packet number in bytes
type PacketNumberLen uint8

const (
	// PacketNumberLenInvalid is the default value and not a valid length for a packet number
	PacketNumberLenInvalid PacketNumberLen = 0
	// PacketNumberLen1 is a packet number length of 1 byte
	PacketNumberLen1 PacketNumberLen = 1
	// PacketNumberLen2 is a packet number length of 2 bytes
	PacketNumberLen2 PacketNumberLen = 2
	// PacketNumberLen4 is a packet number length of 4 bytes
	PacketNumberLen4 PacketNumberLen = 4
	// PacketNumberLen6 is a packet number length of 6 bytes
	PacketNumberLen6 PacketNumberLen = 6
)

// The PacketType is the Long Header Type (only used for the IETF draft header format)
type PacketType uint8

const (
	// PacketTypeInitial is the packet type of an Initial packet
	PacketTypeInitial PacketType = 0x7f
	// PacketTypeRetry is the packet type of a Retry packet
	PacketTypeRetry PacketType = 0x7e
	// PacketTypeHandshake is the packet type of a Handshake packet
	PacketTypeHandshake PacketType = 0x7d
	// PacketType0RTT is the packet type of a 0-RTT packet
	PacketType0RTT PacketType = 0x7c
)

func (t PacketType) String() string {
	switch t {
	case PacketTypeInitial:
		return "Initial"
	case PacketTypeRetry:
		return "Retry"
	case PacketTypeHandshake:
		return "Handshake"
	case PacketType0RTT:
		return "0-RTT Protected"
	default:
		return fmt.Sprintf("unknown packet type: %d", t)
	}
}

// A ByteCount in QUIC
type ByteCount uint64

// MaxByteCount is the maximum value of a ByteCount
const MaxByteCount = ByteCount(1<<62 - 1)

// An ApplicationErrorCode is an application-defined error code.
type ApplicationErrorCode uint16

// MaxReceivePacketSize maximum packet size of any QUIC packet, based on
// ethernet's max size, minus the IP and UDP headers. IPv6 has a 40 byte header,
// UDP adds an additional 8 bytes.  This is a total overhead of 48 bytes.
// Ethernet's max packet size is 1500 bytes,  1500 - 48 = 1452.
const MaxReceivePacketSize ByteCount = 1452

// DefaultTCPMSS is the default maximum packet size used in the Linux TCP implementation.
// Used in QUIC for congestion window computations in bytes.
const DefaultTCPMSS ByteCount = 1460

// MinClientHelloSize is the minimum size the server expects an inchoate CHLO to have (in gQUIC)
const MinClientHelloSize = 1024

// MinInitialPacketSize is the minimum size an Initial packet (in IETF QUIC) is required to have.
const MinInitialPacketSize = 1200

// MaxClientHellos is the maximum number of times we'll send a client hello
// The value 3 accounts for:
// * one failure due to an incorrect or missing source-address token
// * one failure due the server's certificate chain being unavailable and the server being unwilling to send it without a valid source-address token
const MaxClientHellos = 3

// ConnectionIDLenGQUIC is the length of the source Connection ID used on gQUIC QUIC packets.
const ConnectionIDLenGQUIC = 8

// MinConnectionIDLenInitial is the minimum length of the destination connection ID on an Initial packet.
const MinConnectionIDLenInitial = 8
<commit_msg>update mtu in quic<commit_after>package protocol

import (
	"fmt"
)

// A PacketNumber in QUIC
type PacketNumber uint64

// PacketNumberLen is the length of the packet number in bytes
type PacketNumberLen uint8

const (
	// PacketNumberLenInvalid is the default value and not a valid length for a packet number
	PacketNumberLenInvalid PacketNumberLen = 0
	// PacketNumberLen1 is a packet number length of 1 byte
	PacketNumberLen1 PacketNumberLen = 1
	// PacketNumberLen2 is a packet number length of 2 bytes
	PacketNumberLen2 PacketNumberLen = 2
	// PacketNumberLen4 is a packet number length of 4 bytes
	PacketNumberLen4 PacketNumberLen = 4
	// PacketNumberLen6 is a packet number length of 6 bytes
	PacketNumberLen6 PacketNumberLen = 6
)

// The PacketType is the Long Header Type (only used for the IETF draft header format)
type PacketType uint8

const (
	// PacketTypeInitial is the packet type of an Initial packet
	PacketTypeInitial PacketType = 0x7f
	// PacketTypeRetry is the packet type of a Retry packet
	PacketTypeRetry PacketType = 0x7e
	// PacketTypeHandshake is the packet type of a Handshake packet
	PacketTypeHandshake PacketType = 0x7d
	// PacketType0RTT is the packet type of a 0-RTT packet
	PacketType0RTT PacketType = 0x7c
)

func (t PacketType) String() string {
	switch t {
	case PacketTypeInitial:
		return "Initial"
	case PacketTypeRetry:
		return "Retry"
	case PacketTypeHandshake:
		return "Handshake"
	case PacketType0RTT:
		return "0-RTT Protected"
	default:
		return fmt.Sprintf("unknown packet type: %d", t)
	}
}

// A ByteCount in QUIC
type ByteCount uint64

// MaxByteCount is the maximum value of a ByteCount
const MaxByteCount = ByteCount(1<<62 - 1)

// An ApplicationErrorCode is an application-defined error code.
type ApplicationErrorCode uint16

// MaxReceivePacketSize maximum packet size of any QUIC packet, based on
// ethernet's max size, minus the IP and UDP headers. IPv6 has a 40 byte header,
// UDP adds an additional 8 bytes.  This is a total overhead of 48 bytes.
// Ethernet's max packet size is 1500 bytes,  1500 - 48 = 1452.
const MaxReceivePacketSize ByteCount = 1452 - 32

// DefaultTCPMSS is the default maximum packet size used in the Linux TCP implementation.
// Used in QUIC for congestion window computations in bytes.
const DefaultTCPMSS ByteCount = 1460

// MinClientHelloSize is the minimum size the server expects an inchoate CHLO to have (in gQUIC)
const MinClientHelloSize = 1024

// MinInitialPacketSize is the minimum size an Initial packet (in IETF QUIC) is required to have.
const MinInitialPacketSize = 1200

// MaxClientHellos is the maximum number of times we'll send a client hello
// The value 3 accounts for:
// * one failure due to an incorrect or missing source-address token
// * one failure due the server's certificate chain being unavailable and the server being unwilling to send it without a valid source-address token
const MaxClientHellos = 3

// ConnectionIDLenGQUIC is the length of the source Connection ID used on gQUIC QUIC packets.
const ConnectionIDLenGQUIC = 8

// MinConnectionIDLenInitial is the minimum length of the destination connection ID on an Initial packet.
const MinConnectionIDLenInitial = 8
<|endoftext|>


<commit_before>// 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.

// This file was initially generated by gen_to_start.go (add link), as a start
// of the Traffic Ops golang data model

package main

import (
	"database/sql"
	"fmt"
	"os"
	"regexp"
	"strings"
)

func checkErr(err error, txn *sql.Tx) {
	if err != nil {
		fmt.Println("Error 33:", err)
		fmt.Println("Attempting Roll back!")
		txn.Rollback()
		os.Exit(1)
	}
}

func doExec(stmt string, txn *sql.Tx) {
	fmt.Println("  " + stmt)
	_, err := txn.Exec(stmt)
	if err != nil {
		fmt.Println("Error:", err)
		fmt.Println("Attempting Roll back!")
		txn.Rollback()
		os.Exit(1)
	}
}

// Up is executed when this migration is applied
func Up_20170205101432(txn *sql.Tx) {

	algorithmStr := map[int64]string{
		0: "consistent_hash",
		1: "false",
		2: "strict",
		3: "true",
		4: "latched",
	}

	fmt.Println("  Starting migration 20130106222315...")
	doExec("CREATE TYPE profile_type AS ENUM ("+
		"'ATS_PROFILE', 'TR_PROFILE', 'TM_PROFILE', 'TS_PROFILE', 'TP_PROFILE', 'INFLUXDB_PROFILE',"+
		"'RIAK_PROFILE', 'SPLUNK_PROFILE', 'DS_PROFILE', 'ORG_PROFILE', 'KAFKA_PROFILE', 'LOGSTASH_PROFILE',"+
		"'ES_PROFILE', 'UNK_PROFILE')", txn)

	doExec("CREATE OR REPLACE VIEW \"profile_type_values\" AS SELECT unnest(enum_range(NULL::profile_type )) AS value ORDER BY value", txn)

	doExec("ALTER TABLE public.profile ADD COLUMN type profile_type", txn)
	doExec("UPDATE public.profile SET type='UNK_PROFILE'", txn) // So we don't get any NULL, these should be checked.
	doExec("UPDATE public.profile SET type='TR_PROFILE' WHERE name like 'CCR_%' OR name like 'TR_%'", txn)
	doExec("UPDATE public.profile SET type='TM_PROFILE' WHERE name like 'RASCAL_%' OR name like 'TM_%'", txn)
	doExec("UPDATE public.profile SET type='TS_PROFILE' WHERE name like 'TRAFFIC_STATS%'", txn)
	doExec("UPDATE public.profile SET type='TP_PROFILE' WHERE name like 'TRAFFIC_PORTAL%'", txn)
	doExec("UPDATE public.profile SET type='INFLUXDB_PROFILE' WHERE name like 'INFLUXDB%'", txn)
	doExec("UPDATE public.profile SET type='RIAK_PROFILE' WHERE name like 'RIAK%'", txn)
	doExec("UPDATE public.profile SET type='SPLUNK_PROFILE' WHERE name like 'SPLUNK%'", txn)
	doExec("UPDATE public.profile SET type='ORG_PROFILE' WHERE name like '%ORG%' or name like 'MSO%' or name like '%ORIGIN%'", txn)
	doExec("UPDATE public.profile SET type='KAFKA_PROFILE' WHERE name like 'KAFKA%'", txn)
	doExec("UPDATE public.profile SET type='LOGSTASH_PROFILE' WHERE name like 'LOGSTASH_%'", txn)
	doExec("UPDATE public.profile SET type='ES_PROFILE' WHERE name like 'ELASTICSEARCH%'", txn)
	doExec("UPDATE public.profile SET type='ATS_PROFILE' WHERE name like 'EDGE%' or name like 'MID%'", txn)

	doExec("ALTER TABLE public.profile ALTER type SET NOT NULL", txn)

	doExec("ALTER TABLE public.cdn ADD COLUMN domain_name text", txn)

	doExec("UPDATE cdn SET domain_name=domainlist.value "+
		"FROM (SELECT distinct cdn_id,value FROM server,parameter WHERE type=(SELECT id FROM type WHERE name='EDGE') "+
		"AND parameter.id in (select parameter from profile_parameter WHERE profile_parameter.profile=server.profile) "+
		"AND parameter.name='domain_name' "+
		"AND config_file='CRConfig.json') AS domainlist "+
		"WHERE id = domainlist.cdn_id", txn)

	doExec("UPDATE public.cdn SET domain_name='-' WHERE name='ALL'", txn)

	doExec("ALTER TABLE public.cdn ALTER COLUMN domain_name SET NOT NULL", txn)

	doExec("ALTER TABLE public.profile ADD COLUMN cdn bigint", txn)

	doExec("ALTER TABLE public.profile "+
		"ADD CONSTRAINT fk_cdn1 FOREIGN KEY (cdn) "+
		"REFERENCES public.cdn (id) MATCH SIMPLE "+
		"ON UPDATE RESTRICT ON DELETE RESTRICT", txn)

	doExec("CREATE INDEX idx_181818_fk_cdn1 "+
		"ON public.profile "+
		"USING btree "+
		"(cdn)", txn)

	doExec("UPDATE profile set cdn=domainlist.cdn_id "+
		"FROM (SELECT distinct profile.id AS profile_id, value AS profile_domain_name, cdn.id cdn_id "+
		"FROM profile, parameter, cdn, profile_parameter "+
		"WHERE parameter.name='domain_name' "+
		"AND parameter.config_file='CRConfig.json' "+
		"AND parameter.value = cdn.domain_name "+
		"AND parameter.id in (select parameter from profile_parameter where profile=profile.id)) as domainlist "+
		"WHERE id = domainlist.profile_id", txn)

	doExec("ALTER TABLE deliveryservice ALTER profile DROP NOT NULL", txn)

	doExec("UPDATE deliveryservice SET profile=NULL", txn)

	doExec("INSERT INTO parameter (name, config_file, value) VALUES ('mso.parent_retry', 'parent.config', 'simple_retry');", txn)
	doExec("INSERT INTO parameter (name, config_file, value) VALUES ('mso.parent_retry', 'parent.config', 'unavailable_server_retry');", txn)
	doExec("INSERT INTO parameter (name, config_file, value) VALUES ('mso.parent_retry', 'parent.config', 'both');", txn)

	type Profile struct {
		Id                 int64
		Name               string
		Desc               string
		Type               string
		Cdn                int64
		MidHeaderRewrite   string
		MultiSiteOriginAlg int64
		XMLId              string
	}
	// move data
	pmap := make(map[string]Profile)
	rows, err := txn.Query("SELECT id,xml_id,mid_header_rewrite,multi_site_origin,multi_site_origin_algorithm,cdn_id FROM deliveryservice WHERE multi_site_origin=true")
	if err != nil {
		fmt.Println("Error:", err)
		fmt.Println("Attempting Roll back!")
		txn.Rollback()
		os.Exit(1)
	}
	existingParam := make(map[string]int64)
	for rows.Next() {
		var (
			id                          int64
			xml_id                      string
			mid_header_rewrite          sql.NullString
			multi_site_origin           sql.NullBool
			multi_site_origin_algorithm sql.NullInt64
			cdn_id                      int64
		)
		err := rows.Scan(&id, &xml_id, &mid_header_rewrite, &multi_site_origin, &multi_site_origin_algorithm, &cdn_id)
		checkErr(err, txn)

		pName := "DS_" + xml_id
		pDesc := "Deliveryservice profile for " + xml_id
		pType := "DS_PROFILE"
		mhrString := mid_header_rewrite.String
		pmap[pName] = Profile{
			Id:                 -1,
			Name:               pName,
			Desc:               pDesc,
			Type:               pType,
			Cdn:                cdn_id,
			MidHeaderRewrite:   mhrString,
			MultiSiteOriginAlg: multi_site_origin_algorithm.Int64,
			XMLId:              xml_id,
		}
	}
	err = rows.Err()
	checkErr(err, txn)
	rows.Close()

	for _, prof := range pmap {
		fmt.Println("--\nINSERT INTO PROFILE (name, description, type, cdn) VALUES($1, $2, $3, $4) RETURNING id", prof.Name, prof.Desc, prof.Type, prof.Cdn)
		newRow := txn.QueryRow("INSERT INTO PROFILE (name, description, type, cdn) VALUES($1, $2, $3, $4) RETURNING id", prof.Name, prof.Desc, prof.Type, prof.Cdn)
		var newProfileId int64
		err := newRow.Scan(&newProfileId)
		checkErr(err, txn)

		remainingString := ""
		parent_retry := ""
		var regexpOne = regexp.MustCompile(`^\s*set-config\s+proxy.config.http.parent_origin.(\S+)\s+(.*)$`)
		if prof.MidHeaderRewrite != "" {
			remapParts := strings.Split(prof.MidHeaderRewrite, "__RETURN__")
			for _, line := range remapParts {
				fmt.Println(line)
				match := regexpOne.FindSubmatch([]byte(line))
				if len(match) != 0 {
					var newId int64
					var ok bool
					newId, ok = existingParam[string(match[1])+string(match[2])]
					//	fmt.Printf("%s -> %v %v\n", string(match[1])+string(match[2]), newId, ok)
					if !ok {
						if string(match[1]) == "simple_retry_enabled" || string(match[1]) == "dead_server_retry_enabled" {
							if parent_retry == "" {
								parent_retry = string(match[1])
							} else {
								parent_retry = "both"
							}
						} else if string(match[1]) == "dead_server_retry_response_codes" {
							// unavailable_server_retry_responses is the only one that survives?
							//	if string(match[1]) == "dead_server_retry_response_codes" {
							pName := strings.Replace("mso."+string(match[1]), "dead", "unavailable", 1) // "mso.unavailable_server_retry_response_codes"
							pName = strings.Replace(pName, "response_codes", "responses", 1) // "mso.unavailable_server_retry_responses"
							fmt.Println("INSERT INTO PARAMETER (name, config_file, value) VALUES ($1, $2, $3) RETURNING id",
								pName, "parent.config", string(match[2]))
							newRow := txn.QueryRow("INSERT INTO PARAMETER (name, config_file, value) VALUES ($1, $2, $3) RETURNING id",
								pName, "parent.config", string(match[2]))
							err := newRow.Scan(&newId)
							checkErr(err, txn)
							existingParam[string(match[1])+string(match[2])] = newId
						}
					} else {
						newId = existingParam[string(match[1])+string(match[2])]
					}
					if newId != 0 {
						fmt.Println("INSERT INTO PROFILE_PARAMETER (parameter, profile) VALUES ($1, $2)", newId, newProfileId)
						_, err = txn.Exec("INSERT INTO PROFILE_PARAMETER (parameter, profile) VALUES ($1, $2)", newId, newProfileId)
						checkErr(err, txn)
					}
				} else {
					if !strings.HasSuffix(line, "__RETURN__") {
						remainingString = remainingString + line + "__RETURN__"
					}
				}
			}
		}
		/* Not doing the removal of the header_rewrite stuff  at this time, so we can support both 5.x and 6.x - 6.x will have a warning if these are
		   not removed from the DS, but should run just fine.

		fmt.Printf("MHRW was: %s, \nMHRW now: %s\n", prof.MidHeaderRewrite, remainingString)

		_, err = txn.Exec("UPDATE deliveryservice set mid_header_rewrite=$1 where xml_id=$2", remainingString, prof.XMLId)
		checkErr(err, txn)

		*/

		var newId int64
		var ok bool
		newId, ok = existingParam["mso.algorithm"+"parent.config"+algorithmStr[prof.MultiSiteOriginAlg]]
		if !ok {
			fmt.Println("INSERT INTO PARAMETER (name, config_file, value) VALUES ($1, $2, $3) RETURNING id",
				"mso.algorithm", "parent.config", algorithmStr[prof.MultiSiteOriginAlg])
			newRow = txn.QueryRow("INSERT INTO PARAMETER (name, config_file, value) VALUES ($1, $2, $3) RETURNING id",
				"mso.algorithm", "parent.config", algorithmStr[prof.MultiSiteOriginAlg])
			err = newRow.Scan(&newId)
			checkErr(err, txn)
			existingParam["mso.algorithm"+"parent.config"+algorithmStr[prof.MultiSiteOriginAlg]] = newId
		} else {
			newId = existingParam["mso.algorithm"+"parent.config"+algorithmStr[prof.MultiSiteOriginAlg]]
		}

		fmt.Println("INSERT INTO PROFILE_PARAMETER (parameter, profile) VALUES ($1, $2)", newId, newProfileId)
		_, err = txn.Exec("INSERT INTO PROFILE_PARAMETER (parameter, profile) VALUES ($1, $2)", newId, newProfileId)
		checkErr(err, txn)

		fmt.Println("INSERT INTO profile_parameter (profile, parameter) SELECT $1, id FROM parameter "+
			"WHERE config_file='parent.config' AND name='mso.parent_retry' AND value=$2", newProfileId, parent_retry)
		_, err = txn.Exec("INSERT INTO profile_parameter (profile, parameter) SELECT $1, id FROM parameter "+
			"WHERE config_file='parent.config' AND name='mso.parent_retry' AND value=$2", newProfileId, parent_retry)
		checkErr(err, txn)

		_, err = txn.Exec("UPDATE deliveryservice SET profile=$1 WHERE xml_id=$2", newProfileId, prof.XMLId)
		checkErr(err, txn)
	}
}

// Down is executed when this migration is rolled back
func Down_20170205101432(txn *sql.Tx) {
	//
}
<commit_msg>Remove reference to table "public" and match description<commit_after>// 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.

// This file was initially generated by gen_to_start.go (add link), as a start
// of the Traffic Ops golang data model

package main

import (
	"database/sql"
	"fmt"
	"os"
	"regexp"
	"strings"
)

func checkErr(err error, txn *sql.Tx) {
	if err != nil {
		fmt.Println("Error 33:", err)
		fmt.Println("Attempting Roll back!")
		txn.Rollback()
		os.Exit(1)
	}
}

func doExec(stmt string, txn *sql.Tx) {
	fmt.Println("  " + stmt)
	_, err := txn.Exec(stmt)
	if err != nil {
		fmt.Println("Error:", err)
		fmt.Println("Attempting Roll back!")
		txn.Rollback()
		os.Exit(1)
	}
}

// Up is executed when this migration is applied
func Up_20170205101432(txn *sql.Tx) {

	algorithmStr := map[int64]string{
		0: "consistent_hash",
		1: "false",
		2: "strict",
		3: "true",
		4: "latched",
	}

	fmt.Println("  Starting migration 20170205101432.go...")
	doExec("CREATE TYPE profile_type AS ENUM ("+
		"'ATS_PROFILE', 'TR_PROFILE', 'TM_PROFILE', 'TS_PROFILE', 'TP_PROFILE', 'INFLUXDB_PROFILE',"+
		"'RIAK_PROFILE', 'SPLUNK_PROFILE', 'DS_PROFILE', 'ORG_PROFILE', 'KAFKA_PROFILE', 'LOGSTASH_PROFILE',"+
		"'ES_PROFILE', 'UNK_PROFILE')", txn)

	doExec("CREATE OR REPLACE VIEW \"profile_type_values\" AS SELECT unnest(enum_range(NULL::profile_type )) AS value ORDER BY value", txn)

	doExec("ALTER TABLE profile ADD COLUMN type profile_type", txn)
	doExec("UPDATE profile SET type='UNK_PROFILE'", txn) // So we don't get any NULL, these should be checked.
	doExec("UPDATE profile SET type='TR_PROFILE' WHERE name like 'CCR_%' OR name like 'TR_%'", txn)
	doExec("UPDATE profile SET type='TM_PROFILE' WHERE name like 'RASCAL_%' OR name like 'TM_%'", txn)
	doExec("UPDATE profile SET type='TS_PROFILE' WHERE name like 'TRAFFIC_STATS%'", txn)
	doExec("UPDATE profile SET type='TP_PROFILE' WHERE name like 'TRAFFIC_PORTAL%'", txn)
	doExec("UPDATE profile SET type='INFLUXDB_PROFILE' WHERE name like 'INFLUXDB%'", txn)
	doExec("UPDATE profile SET type='RIAK_PROFILE' WHERE name like 'RIAK%'", txn)
	doExec("UPDATE profile SET type='SPLUNK_PROFILE' WHERE name like 'SPLUNK%'", txn)
	doExec("UPDATE profile SET type='ORG_PROFILE' WHERE name like '%ORG%' or name like 'MSO%' or name like '%ORIGIN%'", txn)
	doExec("UPDATE profile SET type='KAFKA_PROFILE' WHERE name like 'KAFKA%'", txn)
	doExec("UPDATE profile SET type='LOGSTASH_PROFILE' WHERE name like 'LOGSTASH_%'", txn)
	doExec("UPDATE profile SET type='ES_PROFILE' WHERE name like 'ELASTICSEARCH%'", txn)
	doExec("UPDATE profile SET type='ATS_PROFILE' WHERE name like 'EDGE%' or name like 'MID%'", txn)

	doExec("ALTER TABLE profile ALTER type SET NOT NULL", txn)

	doExec("ALTER TABLE cdn ADD COLUMN domain_name text", txn)

	doExec("UPDATE cdn SET domain_name=domainlist.value "+
		"FROM (SELECT distinct cdn_id,value FROM server,parameter WHERE type=(SELECT id FROM type WHERE name='EDGE') "+
		"AND parameter.id in (select parameter from profile_parameter WHERE profile_parameter.profile=server.profile) "+
		"AND parameter.name='domain_name' "+
		"AND config_file='CRConfig.json') AS domainlist "+
		"WHERE id = domainlist.cdn_id", txn)

	doExec("UPDATE cdn SET domain_name='-' WHERE name='ALL'", txn)

	doExec("ALTER TABLE cdn ALTER COLUMN domain_name SET NOT NULL", txn)

	doExec("ALTER TABLE profile ADD COLUMN cdn bigint", txn)

	doExec("ALTER TABLE profile "+
		"ADD CONSTRAINT fk_cdn1 FOREIGN KEY (cdn) "+
		"REFERENCES cdn (id) MATCH SIMPLE "+
		"ON UPDATE RESTRICT ON DELETE RESTRICT", txn)

	doExec("CREATE INDEX idx_181818_fk_cdn1 "+
		"ON profile "+
		"USING btree "+
		"(cdn)", txn)

	doExec("UPDATE profile set cdn=domainlist.cdn_id "+
		"FROM (SELECT distinct profile.id AS profile_id, value AS profile_domain_name, cdn.id cdn_id "+
		"FROM profile, parameter, cdn, profile_parameter "+
		"WHERE parameter.name='domain_name' "+
		"AND parameter.config_file='CRConfig.json' "+
		"AND parameter.value = cdn.domain_name "+
		"AND parameter.id in (select parameter from profile_parameter where profile=profile.id)) as domainlist "+
		"WHERE id = domainlist.profile_id", txn)

	doExec("ALTER TABLE deliveryservice ALTER profile DROP NOT NULL", txn)

	doExec("UPDATE deliveryservice SET profile=NULL", txn)

	doExec("INSERT INTO parameter (name, config_file, value) VALUES ('mso.parent_retry', 'parent.config', 'simple_retry');", txn)
	doExec("INSERT INTO parameter (name, config_file, value) VALUES ('mso.parent_retry', 'parent.config', 'unavailable_server_retry');", txn)
	doExec("INSERT INTO parameter (name, config_file, value) VALUES ('mso.parent_retry', 'parent.config', 'both');", txn)

	type Profile struct {
		Id                 int64
		Name               string
		Desc               string
		Type               string
		Cdn                int64
		MidHeaderRewrite   string
		MultiSiteOriginAlg int64
		XMLId              string
	}
	// move data
	pmap := make(map[string]Profile)
	rows, err := txn.Query("SELECT id,xml_id,mid_header_rewrite,multi_site_origin,multi_site_origin_algorithm,cdn_id FROM deliveryservice WHERE multi_site_origin=true")
	if err != nil {
		fmt.Println("Error:", err)
		fmt.Println("Attempting Roll back!")
		txn.Rollback()
		os.Exit(1)
	}
	existingParam := make(map[string]int64)
	for rows.Next() {
		var (
			id                          int64
			xml_id                      string
			mid_header_rewrite          sql.NullString
			multi_site_origin           sql.NullBool
			multi_site_origin_algorithm sql.NullInt64
			cdn_id                      int64
		)
		err := rows.Scan(&id, &xml_id, &mid_header_rewrite, &multi_site_origin, &multi_site_origin_algorithm, &cdn_id)
		checkErr(err, txn)

		pName := "DS_" + xml_id
		pDesc := "Deliveryservice profile for " + xml_id
		pType := "DS_PROFILE"
		mhrString := mid_header_rewrite.String
		pmap[pName] = Profile{
			Id:                 -1,
			Name:               pName,
			Desc:               pDesc,
			Type:               pType,
			Cdn:                cdn_id,
			MidHeaderRewrite:   mhrString,
			MultiSiteOriginAlg: multi_site_origin_algorithm.Int64,
			XMLId:              xml_id,
		}
	}
	err = rows.Err()
	checkErr(err, txn)
	rows.Close()

	for _, prof := range pmap {
		fmt.Println("--\nINSERT INTO PROFILE (name, description, type, cdn) VALUES($1, $2, $3, $4) RETURNING id", prof.Name, prof.Desc, prof.Type, prof.Cdn)
		newRow := txn.QueryRow("INSERT INTO PROFILE (name, description, type, cdn) VALUES($1, $2, $3, $4) RETURNING id", prof.Name, prof.Desc, prof.Type, prof.Cdn)
		var newProfileId int64
		err := newRow.Scan(&newProfileId)
		checkErr(err, txn)

		remainingString := ""
		parent_retry := ""
		var regexpOne = regexp.MustCompile(`^\s*set-config\s+proxy.config.http.parent_origin.(\S+)\s+(.*)$`)
		if prof.MidHeaderRewrite != "" {
			remapParts := strings.Split(prof.MidHeaderRewrite, "__RETURN__")
			for _, line := range remapParts {
				fmt.Println(line)
				match := regexpOne.FindSubmatch([]byte(line))
				if len(match) != 0 {
					var newId int64
					var ok bool
					newId, ok = existingParam[string(match[1])+string(match[2])]
					//	fmt.Printf("%s -> %v %v\n", string(match[1])+string(match[2]), newId, ok)
					if !ok {
						if string(match[1]) == "simple_retry_enabled" || string(match[1]) == "dead_server_retry_enabled" {
							if parent_retry == "" {
								parent_retry = string(match[1])
							} else {
								parent_retry = "both"
							}
						} else if string(match[1]) == "dead_server_retry_response_codes" {
							// unavailable_server_retry_responses is the only one that survives?
							//	if string(match[1]) == "dead_server_retry_response_codes" {
							pName := strings.Replace("mso."+string(match[1]), "dead", "unavailable", 1) // "mso.unavailable_server_retry_response_codes"
							pName = strings.Replace(pName, "response_codes", "responses", 1) // "mso.unavailable_server_retry_responses"
							fmt.Println("INSERT INTO PARAMETER (name, config_file, value) VALUES ($1, $2, $3) RETURNING id",
								pName, "parent.config", string(match[2]))
							newRow := txn.QueryRow("INSERT INTO PARAMETER (name, config_file, value) VALUES ($1, $2, $3) RETURNING id",
								pName, "parent.config", string(match[2]))
							err := newRow.Scan(&newId)
							checkErr(err, txn)
							existingParam[string(match[1])+string(match[2])] = newId
						}
					} else {
						newId = existingParam[string(match[1])+string(match[2])]
					}
					if newId != 0 {
						fmt.Println("INSERT INTO PROFILE_PARAMETER (parameter, profile) VALUES ($1, $2)", newId, newProfileId)
						_, err = txn.Exec("INSERT INTO PROFILE_PARAMETER (parameter, profile) VALUES ($1, $2)", newId, newProfileId)
						checkErr(err, txn)
					}
				} else {
					if !strings.HasSuffix(line, "__RETURN__") {
						remainingString = remainingString + line + "__RETURN__"
					}
				}
			}
		}
		/* Not doing the removal of the header_rewrite stuff  at this time, so we can support both 5.x and 6.x - 6.x will have a warning if these are
		   not removed from the DS, but should run just fine.

		fmt.Printf("MHRW was: %s, \nMHRW now: %s\n", prof.MidHeaderRewrite, remainingString)

		_, err = txn.Exec("UPDATE deliveryservice set mid_header_rewrite=$1 where xml_id=$2", remainingString, prof.XMLId)
		checkErr(err, txn)

		*/

		var newId int64
		var ok bool
		newId, ok = existingParam["mso.algorithm"+"parent.config"+algorithmStr[prof.MultiSiteOriginAlg]]
		if !ok {
			fmt.Println("INSERT INTO PARAMETER (name, config_file, value) VALUES ($1, $2, $3) RETURNING id",
				"mso.algorithm", "parent.config", algorithmStr[prof.MultiSiteOriginAlg])
			newRow = txn.QueryRow("INSERT INTO PARAMETER (name, config_file, value) VALUES ($1, $2, $3) RETURNING id",
				"mso.algorithm", "parent.config", algorithmStr[prof.MultiSiteOriginAlg])
			err = newRow.Scan(&newId)
			checkErr(err, txn)
			existingParam["mso.algorithm"+"parent.config"+algorithmStr[prof.MultiSiteOriginAlg]] = newId
		} else {
			newId = existingParam["mso.algorithm"+"parent.config"+algorithmStr[prof.MultiSiteOriginAlg]]
		}

		fmt.Println("INSERT INTO PROFILE_PARAMETER (parameter, profile) VALUES ($1, $2)", newId, newProfileId)
		_, err = txn.Exec("INSERT INTO PROFILE_PARAMETER (parameter, profile) VALUES ($1, $2)", newId, newProfileId)
		checkErr(err, txn)

		fmt.Println("INSERT INTO profile_parameter (profile, parameter) SELECT $1, id FROM parameter "+
			"WHERE config_file='parent.config' AND name='mso.parent_retry' AND value=$2", newProfileId, parent_retry)
		_, err = txn.Exec("INSERT INTO profile_parameter (profile, parameter) SELECT $1, id FROM parameter "+
			"WHERE config_file='parent.config' AND name='mso.parent_retry' AND value=$2", newProfileId, parent_retry)
		checkErr(err, txn)

		_, err = txn.Exec("UPDATE deliveryservice SET profile=$1 WHERE xml_id=$2", newProfileId, prof.XMLId)
		checkErr(err, txn)
	}
}

// Down is executed when this migration is rolled back
func Down_20170205101432(txn *sql.Tx) {
	//
}
<|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 gcscaching_test

import (
	"errors"
	"testing"
	"time"

	"github.com/googlecloudplatform/gcsfuse/timeutil"
	"github.com/jacobsa/gcloud/gcs"
	"github.com/jacobsa/gcloud/gcs/gcscaching"
	"github.com/jacobsa/gcloud/gcs/gcscaching/mock_gcscaching"
	"github.com/jacobsa/gcloud/gcs/mock_gcs"
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/oglemock"
	. "github.com/jacobsa/ogletest"
)

func TestFastStatBucket(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

const ttl = time.Second

type fastStatBucketTest struct {
	cache   mock_gcscaching.MockStatCache
	clock   timeutil.SimulatedClock
	wrapped mock_gcs.MockBucket

	bucket gcs.Bucket
}

func (t *fastStatBucketTest) SetUp(ti *TestInfo) {
	// Set up a fixed, non-zero time.
	t.clock.SetTime(time.Date(2015, 4, 5, 2, 15, 0, 0, time.Local))

	// Set up dependencies.
	t.cache = mock_gcscaching.NewMockStatCache(ti.MockController, "cache")
	t.wrapped = mock_gcs.NewMockBucket(ti.MockController, "wrapped")

	t.bucket = gcscaching.NewFastStatBucket(
		ttl,
		t.cache,
		&t.clock,
		t.wrapped)
}

////////////////////////////////////////////////////////////////////////
// CreateObject
////////////////////////////////////////////////////////////////////////

type CreateObjectTest struct {
	fastStatBucketTest
}

func init() { RegisterTestSuite(&CreateObjectTest{}) }

func (t *CreateObjectTest) CallsEraseAndWrapped() {
	const name = "taco"

	// Erase
	ExpectCall(t.cache, "Erase")(name)

	// Wrapped
	var wrappedReq *gcs.CreateObjectRequest
	ExpectCall(t.wrapped, "CreateObject")(Any(), Any()).
		WillOnce(DoAll(SaveArg(1, &wrappedReq), Return(nil, errors.New(""))))

	// Call
	req := &gcs.CreateObjectRequest{
		Name: name,
	}

	_, _ = t.bucket.CreateObject(nil, req)

	AssertNe(nil, wrappedReq)
	ExpectEq(req, wrappedReq)
}

func (t *CreateObjectTest) WrappedFails() {
	const name = ""
	var err error

	// Erase
	ExpectCall(t.cache, "Erase")(Any())

	// Wrapped
	ExpectCall(t.wrapped, "CreateObject")(Any(), Any()).
		WillOnce(Return(nil, errors.New("taco")))

	// Call
	_, err = t.bucket.CreateObject(nil, &gcs.CreateObjectRequest{})

	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *CreateObjectTest) WrappedSucceeds() {
	const name = "taco"
	var err error

	// Erase
	ExpectCall(t.cache, "Erase")(Any())

	// Wrapped
	obj := &gcs.Object{
		Name:       name,
		Generation: 1234,
	}

	ExpectCall(t.wrapped, "CreateObject")(Any(), Any()).
		WillOnce(Return(obj, nil))

	// Insert
	ExpectCall(t.cache, "Insert")(obj, timeutil.TimeEq(t.clock.Now().Add(ttl)))

	// Call
	o, err := t.bucket.CreateObject(nil, &gcs.CreateObjectRequest{})

	AssertEq(nil, err)
	ExpectEq(obj, o)
}

////////////////////////////////////////////////////////////////////////
// StatObject
////////////////////////////////////////////////////////////////////////

type StatObjectTest struct {
	fastStatBucketTest
}

func init() { RegisterTestSuite(&StatObjectTest{}) }

func (t *StatObjectTest) CallsCache() {
	const name = "taco"

	// LookUp
	ExpectCall(t.cache, "LookUp")(name, timeutil.TimeEq(t.clock.Now())).
		WillOnce(Return(true, &gcs.Object{}))

	// Call
	req := &gcs.StatObjectRequest{
		Name: name,
	}

	_, _ = t.bucket.StatObject(nil, req)
}

func (t *StatObjectTest) CacheHit_Positive() {
	const name = "taco"

	// LookUp
	obj := &gcs.Object{
		Name: name,
	}

	ExpectCall(t.cache, "LookUp")(Any(), Any()).
		WillOnce(Return(true, obj))

	// Call
	req := &gcs.StatObjectRequest{
		Name: name,
	}

	o, err := t.bucket.StatObject(nil, req)
	AssertEq(nil, err)
	ExpectEq(obj, o)
}

func (t *StatObjectTest) CacheHit_Negative() {
	AssertTrue(false, "TODO")
}

func (t *StatObjectTest) CallsWrapped() {
	const name = ""
	req := &gcs.StatObjectRequest{
		Name: name,
	}

	// LookUp
	ExpectCall(t.cache, "LookUp")(Any(), Any()).
		WillOnce(Return(false, nil))

	// Wrapped
	ExpectCall(t.wrapped, "StatObject")(Any(), req).
		WillOnce(Return(nil, errors.New("")))

	// Call
	_, _ = t.bucket.StatObject(nil, req)
}

func (t *StatObjectTest) WrappedFails() {
	const name = ""

	// LookUp
	ExpectCall(t.cache, "LookUp")(Any(), Any()).
		WillOnce(Return(false, nil))

	// Wrapped
	ExpectCall(t.wrapped, "StatObject")(Any(), Any()).
		WillOnce(Return(nil, errors.New("taco")))

	// Call
	req := &gcs.StatObjectRequest{
		Name: name,
	}

	_, err := t.bucket.StatObject(nil, req)
	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *StatObjectTest) WrappedSaysNotFound() {
	AssertTrue(false, "TODO")
}

func (t *StatObjectTest) WrappedSucceeds() {
	const name = "taco"

	// LookUp
	ExpectCall(t.cache, "LookUp")(Any(), Any()).
		WillOnce(Return(false, nil))

	// Wrapped
	obj := &gcs.Object{
		Name: name,
	}

	ExpectCall(t.wrapped, "StatObject")(Any(), Any()).
		WillOnce(Return(obj, nil))

	// Insert
	ExpectCall(t.cache, "Insert")(obj, timeutil.TimeEq(t.clock.Now().Add(ttl)))

	// Call
	req := &gcs.StatObjectRequest{
		Name: name,
	}

	o, err := t.bucket.StatObject(nil, req)
	AssertEq(nil, err)
	ExpectEq(obj, o)
}

////////////////////////////////////////////////////////////////////////
// ListObjects
////////////////////////////////////////////////////////////////////////

type ListObjectsTest struct {
	fastStatBucketTest
}

func init() { RegisterTestSuite(&ListObjectsTest{}) }

func (t *ListObjectsTest) WrappedFails() {
	// Wrapped
	ExpectCall(t.wrapped, "ListObjects")(Any(), Any()).
		WillOnce(Return(nil, errors.New("taco")))

	// Call
	_, err := t.bucket.ListObjects(nil, &gcs.ListObjectsRequest{})
	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *ListObjectsTest) EmptyListing() {
	// Wrapped
	expected := &gcs.Listing{}

	ExpectCall(t.wrapped, "ListObjects")(Any(), Any()).
		WillOnce(Return(expected, nil))

	// Call
	listing, err := t.bucket.ListObjects(nil, &gcs.ListObjectsRequest{})

	AssertEq(nil, err)
	ExpectEq(expected, listing)
}

func (t *ListObjectsTest) NonEmptyListing() {
	// Wrapped
	o0 := &gcs.Object{Name: "taco"}
	o1 := &gcs.Object{Name: "burrito"}

	expected := &gcs.Listing{
		Objects: []*gcs.Object{o0, o1},
	}

	ExpectCall(t.wrapped, "ListObjects")(Any(), Any()).
		WillOnce(Return(expected, nil))

	// Insert
	ExpectCall(t.cache, "Insert")(o0, timeutil.TimeEq(t.clock.Now().Add(ttl)))
	ExpectCall(t.cache, "Insert")(o1, timeutil.TimeEq(t.clock.Now().Add(ttl)))

	// Call
	listing, err := t.bucket.ListObjects(nil, &gcs.ListObjectsRequest{})

	AssertEq(nil, err)
	ExpectEq(expected, listing)
}

////////////////////////////////////////////////////////////////////////
// UpdateObject
////////////////////////////////////////////////////////////////////////

type UpdateObjectTest struct {
	fastStatBucketTest
}

func init() { RegisterTestSuite(&UpdateObjectTest{}) }

func (t *UpdateObjectTest) CallsEraseAndWrapped() {
	const name = "taco"

	// Erase
	ExpectCall(t.cache, "Erase")(name)

	// Wrapped
	var wrappedReq *gcs.UpdateObjectRequest
	ExpectCall(t.wrapped, "UpdateObject")(Any(), Any()).
		WillOnce(DoAll(SaveArg(1, &wrappedReq), Return(nil, errors.New(""))))

	// Call
	req := &gcs.UpdateObjectRequest{
		Name: name,
	}

	_, _ = t.bucket.UpdateObject(nil, req)

	AssertNe(nil, wrappedReq)
	ExpectEq(req, wrappedReq)
}

func (t *UpdateObjectTest) WrappedFails() {
	const name = ""
	var err error

	// Erase
	ExpectCall(t.cache, "Erase")(Any())

	// Wrapped
	ExpectCall(t.wrapped, "UpdateObject")(Any(), Any()).
		WillOnce(Return(nil, errors.New("taco")))

	// Call
	_, err = t.bucket.UpdateObject(nil, &gcs.UpdateObjectRequest{})

	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *UpdateObjectTest) WrappedSucceeds() {
	const name = "taco"
	var err error

	// Erase
	ExpectCall(t.cache, "Erase")(Any())

	// Wrapped
	obj := &gcs.Object{
		Name:       name,
		Generation: 1234,
	}

	ExpectCall(t.wrapped, "UpdateObject")(Any(), Any()).
		WillOnce(Return(obj, nil))

	// Insert
	ExpectCall(t.cache, "Insert")(obj, timeutil.TimeEq(t.clock.Now().Add(ttl)))

	// Call
	o, err := t.bucket.UpdateObject(nil, &gcs.UpdateObjectRequest{})

	AssertEq(nil, err)
	ExpectEq(obj, o)
}

////////////////////////////////////////////////////////////////////////
// DeleteObject
////////////////////////////////////////////////////////////////////////

type DeleteObjectTest struct {
	fastStatBucketTest
}

func init() { RegisterTestSuite(&DeleteObjectTest{}) }

func (t *DeleteObjectTest) CallsEraseAndWrapped() {
	const name = "taco"

	// Erase
	ExpectCall(t.cache, "Erase")(name)

	// Wrapped
	ExpectCall(t.wrapped, "DeleteObject")(Any(), name).
		WillOnce(Return(errors.New("")))

	// Call
	_ = t.bucket.DeleteObject(nil, name)
}

func (t *DeleteObjectTest) WrappedFails() {
	const name = ""
	var err error

	// Erase
	ExpectCall(t.cache, "Erase")(Any())

	// Wrapped
	ExpectCall(t.wrapped, "DeleteObject")(Any(), Any()).
		WillOnce(Return(errors.New("taco")))

	// Call
	err = t.bucket.DeleteObject(nil, name)

	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *DeleteObjectTest) WrappedSucceeds() {
	const name = ""
	var err error

	// Erase
	ExpectCall(t.cache, "Erase")(Any())

	// Wrapped
	ExpectCall(t.wrapped, "DeleteObject")(Any(), Any()).
		WillOnce(Return(nil))

	// Call
	err = t.bucket.DeleteObject(nil, name)
	AssertEq(nil, err)
}
<commit_msg>StatObjectTest.CacheHit_Negative<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 gcscaching_test

import (
	"errors"
	"testing"
	"time"

	"github.com/googlecloudplatform/gcsfuse/timeutil"
	"github.com/jacobsa/gcloud/gcs"
	"github.com/jacobsa/gcloud/gcs/gcscaching"
	"github.com/jacobsa/gcloud/gcs/gcscaching/mock_gcscaching"
	"github.com/jacobsa/gcloud/gcs/mock_gcs"
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/oglemock"
	. "github.com/jacobsa/ogletest"
)

func TestFastStatBucket(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

const ttl = time.Second

type fastStatBucketTest struct {
	cache   mock_gcscaching.MockStatCache
	clock   timeutil.SimulatedClock
	wrapped mock_gcs.MockBucket

	bucket gcs.Bucket
}

func (t *fastStatBucketTest) SetUp(ti *TestInfo) {
	// Set up a fixed, non-zero time.
	t.clock.SetTime(time.Date(2015, 4, 5, 2, 15, 0, 0, time.Local))

	// Set up dependencies.
	t.cache = mock_gcscaching.NewMockStatCache(ti.MockController, "cache")
	t.wrapped = mock_gcs.NewMockBucket(ti.MockController, "wrapped")

	t.bucket = gcscaching.NewFastStatBucket(
		ttl,
		t.cache,
		&t.clock,
		t.wrapped)
}

////////////////////////////////////////////////////////////////////////
// CreateObject
////////////////////////////////////////////////////////////////////////

type CreateObjectTest struct {
	fastStatBucketTest
}

func init() { RegisterTestSuite(&CreateObjectTest{}) }

func (t *CreateObjectTest) CallsEraseAndWrapped() {
	const name = "taco"

	// Erase
	ExpectCall(t.cache, "Erase")(name)

	// Wrapped
	var wrappedReq *gcs.CreateObjectRequest
	ExpectCall(t.wrapped, "CreateObject")(Any(), Any()).
		WillOnce(DoAll(SaveArg(1, &wrappedReq), Return(nil, errors.New(""))))

	// Call
	req := &gcs.CreateObjectRequest{
		Name: name,
	}

	_, _ = t.bucket.CreateObject(nil, req)

	AssertNe(nil, wrappedReq)
	ExpectEq(req, wrappedReq)
}

func (t *CreateObjectTest) WrappedFails() {
	const name = ""
	var err error

	// Erase
	ExpectCall(t.cache, "Erase")(Any())

	// Wrapped
	ExpectCall(t.wrapped, "CreateObject")(Any(), Any()).
		WillOnce(Return(nil, errors.New("taco")))

	// Call
	_, err = t.bucket.CreateObject(nil, &gcs.CreateObjectRequest{})

	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *CreateObjectTest) WrappedSucceeds() {
	const name = "taco"
	var err error

	// Erase
	ExpectCall(t.cache, "Erase")(Any())

	// Wrapped
	obj := &gcs.Object{
		Name:       name,
		Generation: 1234,
	}

	ExpectCall(t.wrapped, "CreateObject")(Any(), Any()).
		WillOnce(Return(obj, nil))

	// Insert
	ExpectCall(t.cache, "Insert")(obj, timeutil.TimeEq(t.clock.Now().Add(ttl)))

	// Call
	o, err := t.bucket.CreateObject(nil, &gcs.CreateObjectRequest{})

	AssertEq(nil, err)
	ExpectEq(obj, o)
}

////////////////////////////////////////////////////////////////////////
// StatObject
////////////////////////////////////////////////////////////////////////

type StatObjectTest struct {
	fastStatBucketTest
}

func init() { RegisterTestSuite(&StatObjectTest{}) }

func (t *StatObjectTest) CallsCache() {
	const name = "taco"

	// LookUp
	ExpectCall(t.cache, "LookUp")(name, timeutil.TimeEq(t.clock.Now())).
		WillOnce(Return(true, &gcs.Object{}))

	// Call
	req := &gcs.StatObjectRequest{
		Name: name,
	}

	_, _ = t.bucket.StatObject(nil, req)
}

func (t *StatObjectTest) CacheHit_Positive() {
	const name = "taco"

	// LookUp
	obj := &gcs.Object{
		Name: name,
	}

	ExpectCall(t.cache, "LookUp")(Any(), Any()).
		WillOnce(Return(true, obj))

	// Call
	req := &gcs.StatObjectRequest{
		Name: name,
	}

	o, err := t.bucket.StatObject(nil, req)
	AssertEq(nil, err)
	ExpectEq(obj, o)
}

func (t *StatObjectTest) CacheHit_Negative() {
	const name = "taco"

	// LookUp
	ExpectCall(t.cache, "LookUp")(Any(), Any()).
		WillOnce(Return(true, nil))

	// Call
	req := &gcs.StatObjectRequest{
		Name: name,
	}

	_, err := t.bucket.StatObject(nil, req)
	ExpectThat(err, HasSameTypeAs(&gcs.NotFoundError{}))
}

func (t *StatObjectTest) CallsWrapped() {
	const name = ""
	req := &gcs.StatObjectRequest{
		Name: name,
	}

	// LookUp
	ExpectCall(t.cache, "LookUp")(Any(), Any()).
		WillOnce(Return(false, nil))

	// Wrapped
	ExpectCall(t.wrapped, "StatObject")(Any(), req).
		WillOnce(Return(nil, errors.New("")))

	// Call
	_, _ = t.bucket.StatObject(nil, req)
}

func (t *StatObjectTest) WrappedFails() {
	const name = ""

	// LookUp
	ExpectCall(t.cache, "LookUp")(Any(), Any()).
		WillOnce(Return(false, nil))

	// Wrapped
	ExpectCall(t.wrapped, "StatObject")(Any(), Any()).
		WillOnce(Return(nil, errors.New("taco")))

	// Call
	req := &gcs.StatObjectRequest{
		Name: name,
	}

	_, err := t.bucket.StatObject(nil, req)
	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *StatObjectTest) WrappedSaysNotFound() {
	AssertTrue(false, "TODO")
}

func (t *StatObjectTest) WrappedSucceeds() {
	const name = "taco"

	// LookUp
	ExpectCall(t.cache, "LookUp")(Any(), Any()).
		WillOnce(Return(false, nil))

	// Wrapped
	obj := &gcs.Object{
		Name: name,
	}

	ExpectCall(t.wrapped, "StatObject")(Any(), Any()).
		WillOnce(Return(obj, nil))

	// Insert
	ExpectCall(t.cache, "Insert")(obj, timeutil.TimeEq(t.clock.Now().Add(ttl)))

	// Call
	req := &gcs.StatObjectRequest{
		Name: name,
	}

	o, err := t.bucket.StatObject(nil, req)
	AssertEq(nil, err)
	ExpectEq(obj, o)
}

////////////////////////////////////////////////////////////////////////
// ListObjects
////////////////////////////////////////////////////////////////////////

type ListObjectsTest struct {
	fastStatBucketTest
}

func init() { RegisterTestSuite(&ListObjectsTest{}) }

func (t *ListObjectsTest) WrappedFails() {
	// Wrapped
	ExpectCall(t.wrapped, "ListObjects")(Any(), Any()).
		WillOnce(Return(nil, errors.New("taco")))

	// Call
	_, err := t.bucket.ListObjects(nil, &gcs.ListObjectsRequest{})
	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *ListObjectsTest) EmptyListing() {
	// Wrapped
	expected := &gcs.Listing{}

	ExpectCall(t.wrapped, "ListObjects")(Any(), Any()).
		WillOnce(Return(expected, nil))

	// Call
	listing, err := t.bucket.ListObjects(nil, &gcs.ListObjectsRequest{})

	AssertEq(nil, err)
	ExpectEq(expected, listing)
}

func (t *ListObjectsTest) NonEmptyListing() {
	// Wrapped
	o0 := &gcs.Object{Name: "taco"}
	o1 := &gcs.Object{Name: "burrito"}

	expected := &gcs.Listing{
		Objects: []*gcs.Object{o0, o1},
	}

	ExpectCall(t.wrapped, "ListObjects")(Any(), Any()).
		WillOnce(Return(expected, nil))

	// Insert
	ExpectCall(t.cache, "Insert")(o0, timeutil.TimeEq(t.clock.Now().Add(ttl)))
	ExpectCall(t.cache, "Insert")(o1, timeutil.TimeEq(t.clock.Now().Add(ttl)))

	// Call
	listing, err := t.bucket.ListObjects(nil, &gcs.ListObjectsRequest{})

	AssertEq(nil, err)
	ExpectEq(expected, listing)
}

////////////////////////////////////////////////////////////////////////
// UpdateObject
////////////////////////////////////////////////////////////////////////

type UpdateObjectTest struct {
	fastStatBucketTest
}

func init() { RegisterTestSuite(&UpdateObjectTest{}) }

func (t *UpdateObjectTest) CallsEraseAndWrapped() {
	const name = "taco"

	// Erase
	ExpectCall(t.cache, "Erase")(name)

	// Wrapped
	var wrappedReq *gcs.UpdateObjectRequest
	ExpectCall(t.wrapped, "UpdateObject")(Any(), Any()).
		WillOnce(DoAll(SaveArg(1, &wrappedReq), Return(nil, errors.New(""))))

	// Call
	req := &gcs.UpdateObjectRequest{
		Name: name,
	}

	_, _ = t.bucket.UpdateObject(nil, req)

	AssertNe(nil, wrappedReq)
	ExpectEq(req, wrappedReq)
}

func (t *UpdateObjectTest) WrappedFails() {
	const name = ""
	var err error

	// Erase
	ExpectCall(t.cache, "Erase")(Any())

	// Wrapped
	ExpectCall(t.wrapped, "UpdateObject")(Any(), Any()).
		WillOnce(Return(nil, errors.New("taco")))

	// Call
	_, err = t.bucket.UpdateObject(nil, &gcs.UpdateObjectRequest{})

	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *UpdateObjectTest) WrappedSucceeds() {
	const name = "taco"
	var err error

	// Erase
	ExpectCall(t.cache, "Erase")(Any())

	// Wrapped
	obj := &gcs.Object{
		Name:       name,
		Generation: 1234,
	}

	ExpectCall(t.wrapped, "UpdateObject")(Any(), Any()).
		WillOnce(Return(obj, nil))

	// Insert
	ExpectCall(t.cache, "Insert")(obj, timeutil.TimeEq(t.clock.Now().Add(ttl)))

	// Call
	o, err := t.bucket.UpdateObject(nil, &gcs.UpdateObjectRequest{})

	AssertEq(nil, err)
	ExpectEq(obj, o)
}

////////////////////////////////////////////////////////////////////////
// DeleteObject
////////////////////////////////////////////////////////////////////////

type DeleteObjectTest struct {
	fastStatBucketTest
}

func init() { RegisterTestSuite(&DeleteObjectTest{}) }

func (t *DeleteObjectTest) CallsEraseAndWrapped() {
	const name = "taco"

	// Erase
	ExpectCall(t.cache, "Erase")(name)

	// Wrapped
	ExpectCall(t.wrapped, "DeleteObject")(Any(), name).
		WillOnce(Return(errors.New("")))

	// Call
	_ = t.bucket.DeleteObject(nil, name)
}

func (t *DeleteObjectTest) WrappedFails() {
	const name = ""
	var err error

	// Erase
	ExpectCall(t.cache, "Erase")(Any())

	// Wrapped
	ExpectCall(t.wrapped, "DeleteObject")(Any(), Any()).
		WillOnce(Return(errors.New("taco")))

	// Call
	err = t.bucket.DeleteObject(nil, name)

	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *DeleteObjectTest) WrappedSucceeds() {
	const name = ""
	var err error

	// Erase
	ExpectCall(t.cache, "Erase")(Any())

	// Wrapped
	ExpectCall(t.wrapped, "DeleteObject")(Any(), Any()).
		WillOnce(Return(nil))

	// Call
	err = t.bucket.DeleteObject(nil, name)
	AssertEq(nil, err)
}
<|endoftext|>


<commit_before>// ***************************************************************************
//
//  Copyright 2017 David (Dizzy) Smith, dizzyd@dizzyd.com
//
//  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 main

import (
	"compress/bzip2"
	"database/sql"
	"fmt"
	"os"
	"path/filepath"

	"regexp"

	"golang.org/x/text/language"
	"golang.org/x/text/message"

	_ "github.com/mattn/go-sqlite3"
)

type Database struct {
	sqlDb     *sql.DB
	sqlDbPath string
	version   string
}

func OpenDatabase() (*Database, error) {
	db := new(Database)

	err := InstallDatabase(true)
	if err != nil {
		return nil, fmt.Errorf("Database not available; try using db.update command")
	}

	db.sqlDbPath = filepath.Join(env().McdexDir, "mcdex.dat")
	sqlDb, err := sql.Open("sqlite3", db.sqlDbPath)
	if err != nil {
		return nil, err
	}

	_, err = sqlDb.Exec("PRAGMA integrity_check;")
	if err != nil {
		return nil, err
	}

	db.sqlDb = sqlDb

	return db, nil
}

func InstallDatabase(skipIfExists bool) error {
	if skipIfExists && fileExists(filepath.Join(env().McdexDir, "mcdex.dat")) {
		return nil
	}

	// Get the latest version
	version, err := readStringFromUrl("http://files.mcdex.net/data/latest.v4")
	if err != nil {
		return err
	}

	// Download the latest data file to mcdex/mcdex.dat
	url := fmt.Sprintf("http://files.mcdex.net/data/mcdex-v4-%s.dat.bz2", version)
	res, err := HttpGet(url)
	if err != nil {
		return fmt.Errorf("Failed to retrieve %s data file: %+v", version, err)
	}
	defer res.Body.Close()

	// Stream the data file to mcdex.dat.tmp
	tmpFileName := filepath.Join(env().McdexDir, "mcdex.dat.tmp")
	err = writeStream(tmpFileName, bzip2.NewReader(res.Body))
	if err != nil {
		return err
	}

	// Open the temporary database and validate it
	tmpDb, err := sql.Open("sqlite3", tmpFileName)
	if err != nil {
		// TODO: Add log entry about the file being corrupt
		return err
	}
	defer tmpDb.Close()

	_, err = tmpDb.Exec("PRAGMA integrity_check;")
	if err != nil {
		return err
	}

	// Force the tmpDb to close so that (on Windows), we can ensure
	// the rename works
	tmpDb.Close()

	// Close the database and rename the tmp file
	err = os.Rename(tmpFileName, filepath.Join(env().McdexDir, "mcdex.dat"))
	if err != nil {
		return fmt.Errorf("Failed to rename mcdex.dat.tmp: %+v", err)
	}
	return nil
}

func (db *Database) listForge(mcvsn string, verbose bool) error {
	rows, err := db.sqlDb.Query("select version, isrec from forge where mcvsn = ? order by version desc", mcvsn)
	switch {
	case err == sql.ErrNoRows:
		return fmt.Errorf("No Forge version found for %s", mcvsn)
	case err != nil:
		return err
	}

	latest := false

	defer rows.Close()
	for rows.Next() {
		var version string
		var isrec bool
		err := rows.Scan(&version, &isrec)
		if err != nil {
			return err
		}
		if isrec {
			fmt.Printf("%s (recommended)\n", version)
		} else if !latest {
			fmt.Printf("%s (latest)\n", version)
			latest = true
		} else if verbose {
			fmt.Printf("%s\n", version)
		}
	}
	return nil
}

func (db *Database) lookupForgeVsn(mcvsn string) (string, error) {
	var forgeVsn string
	err := db.sqlDb.QueryRow("select version from forge where mcvsn = ? and isrec = 1", mcvsn).Scan(&forgeVsn)
	switch {
	case err == sql.ErrNoRows:
		return "", fmt.Errorf("No Forge version found for %s", mcvsn)
	case err != nil:
		return "", err
	}
	return forgeVsn, nil
}

func (db *Database) lookupMcVsn(forgeVsn string) (string, error) {
	var mcVsn string
	err := db.sqlDb.QueryRow("select mcvsn from forge where version = ?", forgeVsn).Scan(&mcVsn)
	switch {
	case err == sql.ErrNoRows:
		return "", fmt.Errorf("No Minecraft version found for %s", mcVsn)
	case err != nil:
		return "", err
	}
	return mcVsn, nil
}

func (db *Database) printProjects(slug, mcvsn string, ptype int) error {
	// Turn the name into a pre-compiled regex
	slugRegex, err := regexp.Compile("(?i)" + slug)
	if err != nil {
		return fmt.Errorf("Failed to convert %s into regex: %s", slug, err)
	}

	query := "select slug, description, downloads from projects where type = ? and projectid in (select projectid from files where version = ?) order by slug"
	if mcvsn == "" {
		query = "select slug, description, downloads from projects where type = ? order by slug"
	}

	rows, err := db.sqlDb.Query(query, ptype, mcvsn)
	if err != nil {
		return fmt.Errorf("Query failed: %+v", err)
	}
	defer rows.Close()

	// For each row, check the name against the pre-compiled regex
	for rows.Next() {
		var slug, desc string
		var downloads int
		err = rows.Scan(&slug, &desc, &downloads)
		if err != nil {
			return err
		}

		if slug == "" || slugRegex.MatchString(slug) {
			msg := message.NewPrinter(language.English)
			msg.Printf("%s | %s | %d downloads\n", slug, desc, downloads)
		}
	}

	return nil
}

func (db *Database) printLatestProjects(mcvsn string, ptype int) error {
	rows, err := db.sqlDb.Query(`select slug, description, downloads from projects
									    where type = ? and projectid in
									    (select projectid from files order by tstamp desc) limit 100`, ptype)
	if err != nil {
		return fmt.Errorf("Query failed: %+v", err)
	}
	defer rows.Close()

	for rows.Next() {
		var modSlug, modDesc string
		var modDownloads int

		err = rows.Scan(&modSlug, &modDesc, &modDownloads)
		if err != nil {
			return err
		}

		msg := message.NewPrinter(language.English)
		msg.Printf("%s | %s | %d downloads\n", modSlug, modDesc, modDownloads)
	}
	return nil
}

func (db *Database) getLatestFileTstamp() (int, error) {
	var tstamp int
	err := db.sqlDb.QueryRow("select value from meta where key = 'dbtunix'").Scan(&tstamp)
	return tstamp, err
}

func (db *Database) findProjectBySlug(slug string, ptype int) (int, error) {
	var modID int
	err := db.sqlDb.QueryRow("select projectid from projects where type = ? and slug = ?", ptype, slug).Scan(&modID)
	switch {
	case err == sql.ErrNoRows:
		return -1, fmt.Errorf("No mod found %s", slug)
	case err != nil:
		return -1, err
	}
	return modID, nil
}

func (db *Database) findSlugByProject(id int) (string, error) {
	var slug string
	err := db.sqlDb.QueryRow("select slug from projects where projectid = ?", id).Scan(&slug)
	switch {
	case err == sql.ErrNoRows:
		return "", fmt.Errorf("no project found %d", id)
	case err != nil:
		return slug, err
	}
	return slug, nil
}

func (db *Database) findModBySlug(slug string) (int, error) {
	return db.findProjectBySlug(slug, 0)
}

func (db *Database) findModByName(name string) (int, error) {
	var modID int
	err := db.sqlDb.QueryRow("select projectid from projects where type = 0 and (name = ? or slug = ?)", name, name).Scan(&modID)
	switch {
	case err == sql.ErrNoRows:
		return -1, fmt.Errorf("No mod found %s", name)
	case err != nil:
		return -1, err
	}
	return modID, nil
}

func (db *Database) getProjectInfo(projectID int) (string, string, string, error) {
	var slug, name, desc string
	err := db.sqlDb.QueryRow("select slug, name, description from projects where projectid = ? and type = 0", projectID).Scan(&slug, &name, &desc)
	if err != nil {
		return "", "", "", fmt.Errorf("failed to get project info for %d: %+v", projectID, err)
	}

	return slug, name, desc, nil
}

func (db *Database) getDeps(fileID int) ([]string, error) {
	var result []string
	rows, err := db.sqlDb.Query("SELECT projectid, level FROM deps WHERE fileid = ? and level == 1", fileID)

	switch {
	case err == sql.ErrNoRows:
		return []string{}, nil
	case err != nil:
		return []string{}, fmt.Errorf("Failed to query deps for %d: %+v", fileID, err)
	}
	defer rows.Close()

	for rows.Next() {
		var projectID, level int
		err = rows.Scan(&projectID, &level)
		if err != nil {
			return []string{}, fmt.Errorf("Failed to query dep rows for %d: %+v", fileID, err)
		}

		// Resolve the project ID to a slug
		var slug string
		err = db.sqlDb.QueryRow("select slug from projects where projectid = ?", projectID).Scan(&slug)
		if err != nil {
			return []string{}, fmt.Errorf("failed to resolve dep project %d to a slug", projectID)
		}

		result = append(result, slug)
	}

	return result, nil
}

func (db *Database) getLatestPackURL(slug string) (string, error) {
	// First try to find the pack by looking for the specific slug
	pid, err := db.findProjectBySlug(slug, 1)
	if err != nil {
		return "", err
	}

	// Find the latest file given the project ID; we don't need to worry about matching the MC version,
	// since modpacks are always locked to a specific version anyways
	var fileID int
	err = db.sqlDb.QueryRow("select fileid from files where projectid = ? order by tstamp desc limit 1", pid).Scan(&fileID)
	switch {
	case err == sql.ErrNoRows:
		return "", fmt.Errorf("No modpack file found for %s", slug)
	case err != nil:
		return "", err
	}

	// Construct a URL using the slug and file ID
	return fmt.Sprintf("https://minecraft.curseforge.com/projects/%d/files/%d/download", pid, fileID), nil

}
<commit_msg>Update to v5 metadata<commit_after>// ***************************************************************************
//
//  Copyright 2017 David (Dizzy) Smith, dizzyd@dizzyd.com
//
//  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 main

import (
	"compress/bzip2"
	"database/sql"
	"fmt"
	"os"
	"path/filepath"

	"regexp"

	"golang.org/x/text/language"
	"golang.org/x/text/message"

	_ "github.com/mattn/go-sqlite3"
)

type Database struct {
	sqlDb     *sql.DB
	sqlDbPath string
	version   string
}

func OpenDatabase() (*Database, error) {
	db := new(Database)

	err := InstallDatabase(true)
	if err != nil {
		return nil, fmt.Errorf("Database not available; try using db.update command")
	}

	db.sqlDbPath = filepath.Join(env().McdexDir, "mcdex.dat")
	sqlDb, err := sql.Open("sqlite3", db.sqlDbPath)
	if err != nil {
		return nil, err
	}

	_, err = sqlDb.Exec("PRAGMA integrity_check;")
	if err != nil {
		return nil, err
	}

	db.sqlDb = sqlDb

	return db, nil
}

func InstallDatabase(skipIfExists bool) error {
	if skipIfExists && fileExists(filepath.Join(env().McdexDir, "mcdex.dat")) {
		return nil
	}

	// Get the latest version
	version, err := readStringFromUrl("http://files.mcdex.net/data/latest.v5")
	if err != nil {
		return err
	}

	// Download the latest data file to mcdex/mcdex.dat
	url := fmt.Sprintf("http://files.mcdex.net/data/mcdex-v5-%s.dat.bz2", version)
	res, err := HttpGet(url)
	if err != nil {
		return fmt.Errorf("Failed to retrieve %s data file: %+v", version, err)
	}
	defer res.Body.Close()

	// Stream the data file to mcdex.dat.tmp
	tmpFileName := filepath.Join(env().McdexDir, "mcdex.dat.tmp")
	err = writeStream(tmpFileName, bzip2.NewReader(res.Body))
	if err != nil {
		return err
	}

	// Open the temporary database and validate it
	tmpDb, err := sql.Open("sqlite3", tmpFileName)
	if err != nil {
		// TODO: Add log entry about the file being corrupt
		return err
	}
	defer tmpDb.Close()

	_, err = tmpDb.Exec("PRAGMA integrity_check;")
	if err != nil {
		return err
	}

	// Force the tmpDb to close so that (on Windows), we can ensure
	// the rename works
	tmpDb.Close()

	// Close the database and rename the tmp file
	err = os.Rename(tmpFileName, filepath.Join(env().McdexDir, "mcdex.dat"))
	if err != nil {
		return fmt.Errorf("Failed to rename mcdex.dat.tmp: %+v", err)
	}
	return nil
}

func (db *Database) listForge(mcvsn string, verbose bool) error {
	rows, err := db.sqlDb.Query("select version, isrec from forge where mcvsn = ? order by version desc", mcvsn)
	switch {
	case err == sql.ErrNoRows:
		return fmt.Errorf("No Forge version found for %s", mcvsn)
	case err != nil:
		return err
	}

	latest := false

	defer rows.Close()
	for rows.Next() {
		var version string
		var isrec bool
		err := rows.Scan(&version, &isrec)
		if err != nil {
			return err
		}
		if isrec {
			fmt.Printf("%s (recommended)\n", version)
		} else if !latest {
			fmt.Printf("%s (latest)\n", version)
			latest = true
		} else if verbose {
			fmt.Printf("%s\n", version)
		}
	}
	return nil
}

func (db *Database) lookupForgeVsn(mcvsn string) (string, error) {
	var forgeVsn string
	err := db.sqlDb.QueryRow("select version from forge where mcvsn = ? and isrec = 1", mcvsn).Scan(&forgeVsn)
	switch {
	case err == sql.ErrNoRows:
		return "", fmt.Errorf("No Forge version found for %s", mcvsn)
	case err != nil:
		return "", err
	}
	return forgeVsn, nil
}

func (db *Database) lookupMcVsn(forgeVsn string) (string, error) {
	var mcVsn string
	err := db.sqlDb.QueryRow("select mcvsn from forge where version = ?", forgeVsn).Scan(&mcVsn)
	switch {
	case err == sql.ErrNoRows:
		return "", fmt.Errorf("No Minecraft version found for %s", mcVsn)
	case err != nil:
		return "", err
	}
	return mcVsn, nil
}

func (db *Database) printProjects(slug, mcvsn string, ptype int) error {
	// Turn the name into a pre-compiled regex
	slugRegex, err := regexp.Compile("(?i)" + slug)
	if err != nil {
		return fmt.Errorf("Failed to convert %s into regex: %s", slug, err)
	}

	query := "select slug, description, downloads from projects where type = ? and projectid in (select projectid from files where version = ?) order by slug"
	if mcvsn == "" {
		query = "select slug, description, downloads from projects where type = ? order by slug"
	}

	rows, err := db.sqlDb.Query(query, ptype, mcvsn)
	if err != nil {
		return fmt.Errorf("Query failed: %+v", err)
	}
	defer rows.Close()

	// For each row, check the name against the pre-compiled regex
	for rows.Next() {
		var slug, desc string
		var downloads int
		err = rows.Scan(&slug, &desc, &downloads)
		if err != nil {
			return err
		}

		if slug == "" || slugRegex.MatchString(slug) {
			msg := message.NewPrinter(language.English)
			msg.Printf("%s | %s | %d downloads\n", slug, desc, downloads)
		}
	}

	return nil
}

func (db *Database) printLatestProjects(mcvsn string, ptype int) error {
	rows, err := db.sqlDb.Query(`select slug, description, downloads from projects
									    where type = ? and projectid in
									    (select projectid from files order by tstamp desc) limit 100`, ptype)
	if err != nil {
		return fmt.Errorf("Query failed: %+v", err)
	}
	defer rows.Close()

	for rows.Next() {
		var modSlug, modDesc string
		var modDownloads int

		err = rows.Scan(&modSlug, &modDesc, &modDownloads)
		if err != nil {
			return err
		}

		msg := message.NewPrinter(language.English)
		msg.Printf("%s | %s | %d downloads\n", modSlug, modDesc, modDownloads)
	}
	return nil
}

func (db *Database) getLatestFileTstamp() (int, error) {
	var tstamp int
	err := db.sqlDb.QueryRow("select value from meta where key = 'dbtunix'").Scan(&tstamp)
	return tstamp, err
}

func (db *Database) findProjectBySlug(slug string, ptype int) (int, error) {
	var modID int
	err := db.sqlDb.QueryRow("select projectid from projects where type = ? and slug = ?", ptype, slug).Scan(&modID)
	switch {
	case err == sql.ErrNoRows:
		return -1, fmt.Errorf("No mod found %s", slug)
	case err != nil:
		return -1, err
	}
	return modID, nil
}

func (db *Database) findSlugByProject(id int) (string, error) {
	var slug string
	err := db.sqlDb.QueryRow("select slug from projects where projectid = ?", id).Scan(&slug)
	switch {
	case err == sql.ErrNoRows:
		return "", fmt.Errorf("no project found %d", id)
	case err != nil:
		return slug, err
	}
	return slug, nil
}

func (db *Database) findModBySlug(slug string) (int, error) {
	return db.findProjectBySlug(slug, 0)
}

func (db *Database) findModByName(name string) (int, error) {
	var modID int
	err := db.sqlDb.QueryRow("select projectid from projects where type = 0 and (name = ? or slug = ?)", name, name).Scan(&modID)
	switch {
	case err == sql.ErrNoRows:
		return -1, fmt.Errorf("No mod found %s", name)
	case err != nil:
		return -1, err
	}
	return modID, nil
}

func (db *Database) getProjectInfo(projectID int) (string, string, string, error) {
	var slug, name, desc string
	err := db.sqlDb.QueryRow("select slug, name, description from projects where projectid = ? and type = 0", projectID).Scan(&slug, &name, &desc)
	if err != nil {
		return "", "", "", fmt.Errorf("failed to get project info for %d: %+v", projectID, err)
	}

	return slug, name, desc, nil
}

func (db *Database) getDeps(fileID int) ([]string, error) {
	var result []string
	rows, err := db.sqlDb.Query("SELECT projectid, level FROM deps WHERE fileid = ? and level == 1", fileID)

	switch {
	case err == sql.ErrNoRows:
		return []string{}, nil
	case err != nil:
		return []string{}, fmt.Errorf("Failed to query deps for %d: %+v", fileID, err)
	}
	defer rows.Close()

	for rows.Next() {
		var projectID, level int
		err = rows.Scan(&projectID, &level)
		if err != nil {
			return []string{}, fmt.Errorf("Failed to query dep rows for %d: %+v", fileID, err)
		}

		// Resolve the project ID to a slug
		var slug string
		err = db.sqlDb.QueryRow("select slug from projects where projectid = ?", projectID).Scan(&slug)
		if err != nil {
			return []string{}, fmt.Errorf("failed to resolve dep project %d to a slug", projectID)
		}

		result = append(result, slug)
	}

	return result, nil
}

func (db *Database) getLatestPackURL(slug string) (string, error) {
	// First try to find the pack by looking for the specific slug
	pid, err := db.findProjectBySlug(slug, 1)
	if err != nil {
		return "", err
	}

	// Find the latest file given the project ID; we don't need to worry about matching the MC version,
	// since modpacks are always locked to a specific version anyways
	var fileID int
	err = db.sqlDb.QueryRow("select fileid from files where projectid = ? order by tstamp desc limit 1", pid).Scan(&fileID)
	switch {
	case err == sql.ErrNoRows:
		return "", fmt.Errorf("No modpack file found for %s", slug)
	case err != nil:
		return "", err
	}

	// Construct a URL using the slug and file ID
	return fmt.Sprintf("https://minecraft.curseforge.com/projects/%d/files/%d/download", pid, fileID), nil

}
<|endoftext|>