<commit_before>/*
Copyright IBM Corp All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/

package lifecycle

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"syscall"

	docker "github.com/fsouza/go-dockerclient"
	"github.com/gogo/protobuf/proto"
	"github.com/hyperledger/fabric/common/tools/protolator"
	"github.com/hyperledger/fabric/common/tools/protolator/protoext/ordererext"
	"github.com/hyperledger/fabric/common/util"
	"github.com/hyperledger/fabric/integration/nwo"
	"github.com/hyperledger/fabric/integration/nwo/commands"
	"github.com/hyperledger/fabric/protos/common"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
	"github.com/onsi/gomega/gexec"
	"github.com/tedsuo/ifrit"
	"gopkg.in/yaml.v2"
)

var _ = Describe("Lifecycle", func() {
	var (
		client    *docker.Client
		tempDir   string
		network   *nwo.Network
		processes = map[string]ifrit.Process{}
	)

	BeforeEach(func() {
		var err error
		tempDir, err = ioutil.TempDir("", "nwo")
		Expect(err).NotTo(HaveOccurred())

		client, err = docker.NewClientFromEnv()
		Expect(err).NotTo(HaveOccurred())

		soloBytes, err := ioutil.ReadFile("solo.yaml")
		Expect(err).NotTo(HaveOccurred())

		var config *nwo.Config
		err = yaml.Unmarshal(soloBytes, &config)
		Expect(err).NotTo(HaveOccurred())

		network = nwo.New(config, tempDir, client, StartPort(), components)

		// Generate config and bootstrap the network
		network.GenerateConfigTree()
		network.Bootstrap()

		for _, o := range network.Orderers {
			or := network.OrdererRunner(o)
			p := ifrit.Invoke(or)
			processes[o.ID()] = p
			Eventually(p.Ready(), network.EventuallyTimeout).Should(BeClosed())
		}

		for _, peer := range network.Peers {
			pr := network.PeerRunner(peer)
			p := ifrit.Invoke(pr)
			processes[peer.ID()] = p
			Eventually(p.Ready(), network.EventuallyTimeout).Should(BeClosed())
		}
	})

	AfterEach(func() {
		// Shutdown processes and cleanup
		for _, p := range processes {
			p.Signal(syscall.SIGTERM)
			Eventually(p.Wait(), network.EventuallyTimeout).Should(Receive())
		}
		network.Cleanup()

		os.RemoveAll(tempDir)
	})

	It("deploys and executes chaincode using _lifecycle and upgrades it", func() {
		orderer := network.Orderer("orderer0")
		testPeers := network.PeersWithChannel("testchannel")
		org1peer2 := network.Peer("org1", "peer2")

		chaincode := nwo.Chaincode{
			Name:                "mycc",
			Version:             "0.0",
			Path:                "github.com/hyperledger/fabric/integration/chaincode/simple/cmd",
			Lang:                "golang",
			PackageFile:         filepath.Join(tempDir, "simplecc.tar.gz"),
			Ctor:                `{"Args":["init","a","100","b","200"]}`,
			ChannelConfigPolicy: "/Channel/Application/Endorsement",
			Sequence:            "1",
			InitRequired:        true,
			Label:               "my_simple_chaincode",
		}

		By("setting up the channel")
		network.CreateAndJoinChannels(orderer)
		network.UpdateChannelAnchors(orderer, "testchannel")
		network.VerifyMembership(network.PeersWithChannel("testchannel"), "testchannel")
		nwo.EnableCapabilities(network, "testchannel", "Application", "V2_0", orderer, network.Peer("org1", "peer1"), network.Peer("org2", "peer1"))

		By("deploying the chaincode")
		nwo.PackageChaincode(network, chaincode, testPeers[0])

		// we set the PackageID so that we can pass it to the approve step
		filebytes, err := ioutil.ReadFile(chaincode.PackageFile)
		Expect(err).NotTo(HaveOccurred())
		hashStr := fmt.Sprintf("%x", util.ComputeSHA256(filebytes))
		chaincode.PackageID = chaincode.Label + ":" + hashStr

		nwo.InstallChaincode(network, chaincode, testPeers...)

		nwo.ApproveChaincodeForMyOrg(network, "testchannel", orderer, chaincode, testPeers...)

		nwo.SimulateCommitUntilSuccess(network, "testchannel", chaincode, network.PeerOrgs(), testPeers...)
		nwo.CommitChaincode(network, "testchannel", orderer, chaincode, testPeers[0], testPeers...)
		nwo.InitChaincode(network, "testchannel", orderer, chaincode, testPeers...)

		By("ensuring the chaincode can be invoked and queried")
		RunQueryInvokeQuery(network, orderer, org1peer2, 100)

		By("setting a bad package ID to temporarily disable endorsements on org1")
		savedPackageID := chaincode.PackageID
		// note that in theory it should be sufficient to set it to an
		// empty string, but the ApproveChaincodeForMyOrg
		// function fills the packageID field if empty
		chaincode.PackageID = "bad"
		nwo.ApproveChaincodeForMyOrg(network, "testchannel", orderer, chaincode, org1peer2)

		By("querying the chaincode and expecting the invocation to fail")
		sess, err := network.PeerUserSession(org1peer2, "User1", commands.ChaincodeQuery{
			ChannelID: "testchannel",
			Name:      "mycc",
			Ctor:      `{"Args":["query","a"]}`,
		})
		Expect(err).NotTo(HaveOccurred())
		Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(1))
		Expect(sess.Err).To(gbytes.Say("Error: endorsement failure during query. response: status:500 " +
			"message:\"make sure the chaincode mycc has been successfully defined on channel testchannel and try " +
			"again: chaincode definition for 'mycc' exists, but chaincode is not installed\""))

		By("setting the correct package ID to restore the chaincode")
		chaincode.PackageID = savedPackageID
		nwo.ApproveChaincodeForMyOrg(network, "testchannel", orderer, chaincode, org1peer2)

		By("querying the chaincode and expecting the invocation to succeed")
		sess, err = network.PeerUserSession(org1peer2, "User1", commands.ChaincodeQuery{
			ChannelID: "testchannel",
			Name:      "mycc",
			Ctor:      `{"Args":["query","a"]}`,
		})
		Expect(err).NotTo(HaveOccurred())
		Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(0))
		Expect(sess).To(gbytes.Say("90"))

		By("upgrading the chaincode to sequence 2")
		chaincode.Sequence = "2"

		nwo.ApproveChaincodeForMyOrg(network, "testchannel", orderer, chaincode, testPeers...)

		nwo.SimulateCommitUntilSuccess(network, "testchannel", chaincode, network.PeerOrgs(), testPeers...)
		nwo.CommitChaincode(network, "testchannel", orderer, chaincode, testPeers[0], testPeers...)

		By("ensuring the chaincode can still be invoked and queried")
		RunQueryInvokeQuery(network, orderer, testPeers[0], 90)

		By("adding a new org")
		org3 := &nwo.Organization{
			MSPID:         "Org3ExampleCom",
			Name:          "org3",
			Domain:        "org3.example.com",
			EnableNodeOUs: true,
			Users:         2,
			CA: &nwo.CA{
				Hostname: "ca",
			},
		}

		org3peer1 := &nwo.Peer{
			Name:         "peer1",
			Organization: "org3",
			Channels:     testPeers[0].Channels,
		}
		org3peer2 := &nwo.Peer{
			Name:         "peer2",
			Organization: "org3",
			Channels:     testPeers[0].Channels,
		}
		org3Peers := []*nwo.Peer{org3peer1, org3peer2}

		network.AddOrg(org3, org3peer1, org3peer2)
		network.GenerateOrgUpdateMaterials(org3peer1, org3peer2)

		By("starting the org3 peers")
		for _, peer := range org3Peers {
			pr := network.PeerRunner(peer)
			p := ifrit.Invoke(pr)
			processes[peer.ID()] = p
			Eventually(p.Ready(), network.EventuallyTimeout).Should(BeClosed())
		}

		By("updating the channel config to include org3")
		// get the current channel config
		currentConfig := nwo.GetConfig(network, testPeers[0], orderer, "testchannel")
		updatedConfig := proto.Clone(currentConfig).(*common.Config)

		// get the configtx info for org3
		sess, err = network.ConfigTxGen(commands.PrintOrg{
			ConfigPath: network.RootDir,
			PrintOrg:   "org3",
		})
		Expect(err).NotTo(HaveOccurred())
		Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(0))
		org3Group := &ordererext.DynamicOrdererOrgGroup{ConfigGroup: &common.ConfigGroup{}}
		err = protolator.DeepUnmarshalJSON(bytes.NewBuffer(sess.Out.Contents()), org3Group)
		Expect(err).NotTo(HaveOccurred())

		// update the channel config to include org3
		updatedConfig.ChannelGroup.Groups["Application"].Groups["org3"] = org3Group.ConfigGroup
		nwo.UpdateConfig(network, orderer, "testchannel", currentConfig, updatedConfig, true, testPeers[0], testPeers...)

		By("joining the org3 peers to the channel")
		network.JoinChannel("testchannel", orderer, org3peer1, org3peer2)

		// update testPeers now that org3 has joined
		testPeers = network.PeersWithChannel("testchannel")

		// wait until all peers, particularly those in org3, have received the block
		// containing the updated config
		maxLedgerHeight := nwo.GetMaxLedgerHeight(network, "testchannel", testPeers...)
		nwo.WaitUntilEqualLedgerHeight(network, "testchannel", maxLedgerHeight, testPeers...)

		By("installing the chaincode to the org3 peers")
		nwo.InstallChaincode(network, chaincode, org3peer1, org3peer2)

		By("ensuring org3 peers do not execute the chaincode before approving the definition")
		org3AndOrg1PeerAddresses := []string{
			network.PeerAddress(org3peer1, nwo.ListenPort),
			network.PeerAddress(org1peer2, nwo.ListenPort),
		}

		sess, err = network.PeerUserSession(org3peer1, "User1", commands.ChaincodeInvoke{
			ChannelID:     "testchannel",
			Orderer:       network.OrdererAddress(orderer, nwo.ListenPort),
			Name:          "mycc",
			Ctor:          `{"Args":["invoke","a","b","10"]}`,
			PeerAddresses: org3AndOrg1PeerAddresses,
			WaitForEvent:  true,
		})
		Expect(err).NotTo(HaveOccurred())
		Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(1))
		Expect(sess.Err).To(gbytes.Say("chaincode definition for 'mycc' at sequence 2 on channel 'testchannel' has not yet been approved by this org"))

		By("org3 approving the chaincode definition")
		nwo.ApproveChaincodeForMyOrg(network, "testchannel", orderer, chaincode, network.PeersInOrg("org3")...)
		nwo.EnsureCommitted(network, "testchannel", chaincode.Name, chaincode.Version, chaincode.Sequence, org3peer1)

		By("ensuring chaincode can be invoked and queried by org3")
		RunQueryInvokeQueryWithAddresses(network, orderer, org3peer1, 80, org3AndOrg1PeerAddresses...)
	})
})
<commit_msg>[FAB-15872] Added test for default policy in chaincode<commit_after>/*
Copyright IBM Corp All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/

package lifecycle

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"syscall"

	docker "github.com/fsouza/go-dockerclient"
	"github.com/gogo/protobuf/proto"
	"github.com/hyperledger/fabric/common/tools/protolator"
	"github.com/hyperledger/fabric/common/tools/protolator/protoext/ordererext"
	"github.com/hyperledger/fabric/common/util"
	"github.com/hyperledger/fabric/integration/nwo"
	"github.com/hyperledger/fabric/integration/nwo/commands"
	"github.com/hyperledger/fabric/protos/common"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
	"github.com/onsi/gomega/gexec"
	"github.com/tedsuo/ifrit"
	"gopkg.in/yaml.v2"
)

var _ = Describe("Lifecycle", func() {
	var (
		client    *docker.Client
		tempDir   string
		network   *nwo.Network
		processes = map[string]ifrit.Process{}
	)

	BeforeEach(func() {
		var err error
		tempDir, err = ioutil.TempDir("", "nwo")
		Expect(err).NotTo(HaveOccurred())

		client, err = docker.NewClientFromEnv()
		Expect(err).NotTo(HaveOccurred())

		soloBytes, err := ioutil.ReadFile("solo.yaml")
		Expect(err).NotTo(HaveOccurred())

		var config *nwo.Config
		err = yaml.Unmarshal(soloBytes, &config)
		Expect(err).NotTo(HaveOccurred())

		network = nwo.New(config, tempDir, client, StartPort(), components)

		// Generate config and bootstrap the network
		network.GenerateConfigTree()
		network.Bootstrap()

		for _, o := range network.Orderers {
			or := network.OrdererRunner(o)
			p := ifrit.Invoke(or)
			processes[o.ID()] = p
			Eventually(p.Ready(), network.EventuallyTimeout).Should(BeClosed())
		}

		for _, peer := range network.Peers {
			pr := network.PeerRunner(peer)
			p := ifrit.Invoke(pr)
			processes[peer.ID()] = p
			Eventually(p.Ready(), network.EventuallyTimeout).Should(BeClosed())
		}
	})

	AfterEach(func() {
		// Shutdown processes and cleanup
		for _, p := range processes {
			p.Signal(syscall.SIGTERM)
			Eventually(p.Wait(), network.EventuallyTimeout).Should(Receive())
		}
		network.Cleanup()

		os.RemoveAll(tempDir)
	})

	It("deploys and executes chaincode using _lifecycle and upgrades it", func() {
		orderer := network.Orderer("orderer0")
		testPeers := network.PeersWithChannel("testchannel")
		org1peer2 := network.Peer("org1", "peer2")

		chaincode := nwo.Chaincode{
			Name:                "mycc",
			Version:             "0.0",
			Path:                "github.com/hyperledger/fabric/integration/chaincode/simple/cmd",
			Lang:                "golang",
			PackageFile:         filepath.Join(tempDir, "simplecc.tar.gz"),
			Ctor:                `{"Args":["init","a","100","b","200"]}`,
			ChannelConfigPolicy: "/Channel/Application/Endorsement",
			Sequence:            "1",
			InitRequired:        true,
			Label:               "my_simple_chaincode",
		}

		By("setting up the channel")
		network.CreateAndJoinChannels(orderer)
		network.UpdateChannelAnchors(orderer, "testchannel")
		network.VerifyMembership(network.PeersWithChannel("testchannel"), "testchannel")
		nwo.EnableCapabilities(network, "testchannel", "Application", "V2_0", orderer, network.Peer("org1", "peer1"), network.Peer("org2", "peer1"))

		By("deploying the chaincode")
		nwo.PackageChaincode(network, chaincode, testPeers[0])

		// we set the PackageID so that we can pass it to the approve step
		filebytes, err := ioutil.ReadFile(chaincode.PackageFile)
		Expect(err).NotTo(HaveOccurred())
		hashStr := fmt.Sprintf("%x", util.ComputeSHA256(filebytes))
		chaincode.PackageID = chaincode.Label + ":" + hashStr

		nwo.InstallChaincode(network, chaincode, testPeers...)

		nwo.ApproveChaincodeForMyOrg(network, "testchannel", orderer, chaincode, testPeers...)

		nwo.SimulateCommitUntilSuccess(network, "testchannel", chaincode, network.PeerOrgs(), testPeers...)
		nwo.CommitChaincode(network, "testchannel", orderer, chaincode, testPeers[0], testPeers...)
		nwo.InitChaincode(network, "testchannel", orderer, chaincode, testPeers...)

		By("ensuring the chaincode can be invoked and queried")
		RunQueryInvokeQuery(network, orderer, org1peer2, 100)

		By("setting a bad package ID to temporarily disable endorsements on org1")
		savedPackageID := chaincode.PackageID
		// note that in theory it should be sufficient to set it to an
		// empty string, but the ApproveChaincodeForMyOrg
		// function fills the packageID field if empty
		chaincode.PackageID = "bad"
		nwo.ApproveChaincodeForMyOrg(network, "testchannel", orderer, chaincode, org1peer2)

		By("querying the chaincode and expecting the invocation to fail")
		sess, err := network.PeerUserSession(org1peer2, "User1", commands.ChaincodeQuery{
			ChannelID: "testchannel",
			Name:      "mycc",
			Ctor:      `{"Args":["query","a"]}`,
		})
		Expect(err).NotTo(HaveOccurred())
		Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(1))
		Expect(sess.Err).To(gbytes.Say("Error: endorsement failure during query. response: status:500 " +
			"message:\"make sure the chaincode mycc has been successfully defined on channel testchannel and try " +
			"again: chaincode definition for 'mycc' exists, but chaincode is not installed\""))

		By("setting the correct package ID to restore the chaincode")
		chaincode.PackageID = savedPackageID
		nwo.ApproveChaincodeForMyOrg(network, "testchannel", orderer, chaincode, org1peer2)

		By("querying the chaincode and expecting the invocation to succeed")
		sess, err = network.PeerUserSession(org1peer2, "User1", commands.ChaincodeQuery{
			ChannelID: "testchannel",
			Name:      "mycc",
			Ctor:      `{"Args":["query","a"]}`,
		})
		Expect(err).NotTo(HaveOccurred())
		Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(0))
		Expect(sess).To(gbytes.Say("90"))

		By("upgrading the chaincode to sequence 2")
		chaincode.Sequence = "2"

		nwo.ApproveChaincodeForMyOrg(network, "testchannel", orderer, chaincode, testPeers...)

		nwo.SimulateCommitUntilSuccess(network, "testchannel", chaincode, network.PeerOrgs(), testPeers...)
		nwo.CommitChaincode(network, "testchannel", orderer, chaincode, testPeers[0], testPeers...)

		By("ensuring the chaincode can still be invoked and queried")
		RunQueryInvokeQuery(network, orderer, testPeers[0], 90)

		By("adding a new org")
		org3 := &nwo.Organization{
			MSPID:         "Org3ExampleCom",
			Name:          "org3",
			Domain:        "org3.example.com",
			EnableNodeOUs: true,
			Users:         2,
			CA: &nwo.CA{
				Hostname: "ca",
			},
		}

		org3peer1 := &nwo.Peer{
			Name:         "peer1",
			Organization: "org3",
			Channels:     testPeers[0].Channels,
		}
		org3peer2 := &nwo.Peer{
			Name:         "peer2",
			Organization: "org3",
			Channels:     testPeers[0].Channels,
		}
		org3Peers := []*nwo.Peer{org3peer1, org3peer2}

		network.AddOrg(org3, org3peer1, org3peer2)
		network.GenerateOrgUpdateMaterials(org3peer1, org3peer2)

		By("starting the org3 peers")
		for _, peer := range org3Peers {
			pr := network.PeerRunner(peer)
			p := ifrit.Invoke(pr)
			processes[peer.ID()] = p
			Eventually(p.Ready(), network.EventuallyTimeout).Should(BeClosed())
		}

		By("updating the channel config to include org3")
		// get the current channel config
		currentConfig := nwo.GetConfig(network, testPeers[0], orderer, "testchannel")
		updatedConfig := proto.Clone(currentConfig).(*common.Config)

		// get the configtx info for org3
		sess, err = network.ConfigTxGen(commands.PrintOrg{
			ConfigPath: network.RootDir,
			PrintOrg:   "org3",
		})
		Expect(err).NotTo(HaveOccurred())
		Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(0))
		org3Group := &ordererext.DynamicOrdererOrgGroup{ConfigGroup: &common.ConfigGroup{}}
		err = protolator.DeepUnmarshalJSON(bytes.NewBuffer(sess.Out.Contents()), org3Group)
		Expect(err).NotTo(HaveOccurred())

		// update the channel config to include org3
		updatedConfig.ChannelGroup.Groups["Application"].Groups["org3"] = org3Group.ConfigGroup
		nwo.UpdateConfig(network, orderer, "testchannel", currentConfig, updatedConfig, true, testPeers[0], testPeers...)

		By("joining the org3 peers to the channel")
		network.JoinChannel("testchannel", orderer, org3peer1, org3peer2)

		// update testPeers now that org3 has joined
		testPeers = network.PeersWithChannel("testchannel")

		// wait until all peers, particularly those in org3, have received the block
		// containing the updated config
		maxLedgerHeight := nwo.GetMaxLedgerHeight(network, "testchannel", testPeers...)
		nwo.WaitUntilEqualLedgerHeight(network, "testchannel", maxLedgerHeight, testPeers...)

		By("installing the chaincode to the org3 peers")
		nwo.InstallChaincode(network, chaincode, org3peer1, org3peer2)

		By("ensuring org3 peers do not execute the chaincode before approving the definition")
		org3AndOrg1PeerAddresses := []string{
			network.PeerAddress(org3peer1, nwo.ListenPort),
			network.PeerAddress(org1peer2, nwo.ListenPort),
		}

		sess, err = network.PeerUserSession(org3peer1, "User1", commands.ChaincodeInvoke{
			ChannelID:     "testchannel",
			Orderer:       network.OrdererAddress(orderer, nwo.ListenPort),
			Name:          "mycc",
			Ctor:          `{"Args":["invoke","a","b","10"]}`,
			PeerAddresses: org3AndOrg1PeerAddresses,
			WaitForEvent:  true,
		})
		Expect(err).NotTo(HaveOccurred())
		Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(1))
		Expect(sess.Err).To(gbytes.Say("chaincode definition for 'mycc' at sequence 2 on channel 'testchannel' has not yet been approved by this org"))

		By("org3 approving the chaincode definition")
		nwo.ApproveChaincodeForMyOrg(network, "testchannel", orderer, chaincode, network.PeersInOrg("org3")...)
		nwo.EnsureCommitted(network, "testchannel", chaincode.Name, chaincode.Version, chaincode.Sequence, org3peer1)

		By("ensuring chaincode can be invoked and queried by org3")
		RunQueryInvokeQueryWithAddresses(network, orderer, org3peer1, 80, org3AndOrg1PeerAddresses...)

		By("deploying a chaincode without an endorsement policy specified")
		chaincode = nwo.Chaincode{
			Name:         "defaultpolicycc",
			Version:      "0.0",
			Path:         "github.com/hyperledger/fabric/integration/chaincode/simple/cmd",
			Lang:         "golang",
			PackageFile:  filepath.Join(tempDir, "simplecc.tar.gz"),
			Ctor:         `{"Args":["init","a","100","b","200"]}`,
			Sequence:     "1",
			InitRequired: true,
			Label:        "my_simple_chaincode",
		}

		nwo.DeployChaincode(network, "testchannel", orderer, chaincode)

		By("attempting to invoke the chaincode without a majority")
		sess, err = network.PeerUserSession(org3peer1, "User1", commands.ChaincodeInvoke{
			ChannelID:    "testchannel",
			Orderer:      network.OrdererAddress(orderer, nwo.ListenPort),
			Name:         "defaultpolicycc",
			Ctor:         `{"Args":["invoke","a","b","10"]}`,
			WaitForEvent: true,
		})
		Expect(err).ToNot(HaveOccurred())
		Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(1))
		Expect(sess.Err).To(gbytes.Say(`\QError: transaction invalidated with status (ENDORSEMENT_POLICY_FAILURE)\E`))

		By("attempting to invoke the chaincode with a majority")
		sess, err = network.PeerUserSession(org3peer1, "User1", commands.ChaincodeInvoke{
			ChannelID:     "testchannel",
			Orderer:       network.OrdererAddress(orderer, nwo.ListenPort),
			Name:          "defaultpolicycc",
			Ctor:          `{"Args":["invoke","a","b","10"]}`,
			PeerAddresses: org3AndOrg1PeerAddresses,
			WaitForEvent:  true,
		})
		Expect(err).NotTo(HaveOccurred())
		Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(0))
		Expect(sess.Err).To(gbytes.Say(`\Qcommitted with status (VALID)\E`))
		Expect(sess.Err).To(gbytes.Say(`Chaincode invoke successful. result: status:200`))
	})
})
<|endoftext|>


<commit_before>package federation

import (
	"context"
	"encoding/json"
	"strings"
	"testing"

	"github.com/samsarahq/thunder/graphql"
	"github.com/samsarahq/thunder/graphql/introspection"
	"github.com/samsarahq/thunder/graphql/schemabuilder"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func makeExecutors(schemas map[string]*schemabuilder.Schema) (map[string]ExecutorClient, error) {
	executors := make(map[string]ExecutorClient)

	for name, schema := range schemas {
		srv, err := NewServer(schema.MustBuild())
		if err != nil {
			return nil, err
		}
		executors[name] = &DirectExecutorClient{Client: srv}
	}

	return executors, nil
}

func createExecutorWithFederatedObjects() (*Executor, *schemabuilder.Schema, *schemabuilder.Schema, error) {
	// The first schema has a user object with an id and orgId
	type User struct {
		Id    int64
		OrgId int64
		Name  string
	}
	s1 := schemabuilder.NewSchema()
	user := s1.Object("User", User{})
	user.Key("id")
	user.Federation(func(u *User) int64 {
		return u.Id
	})
	s1.Query().FieldFunc("users", func(ctx context.Context) ([]*User, error) {
		users := make([]*User, 0, 1)
		users = append(users, &User{Id: int64(1), OrgId: int64(9086)})
		return users, nil
	})

	s1.Query().FieldFunc("usersWithArgs", func(args struct {
		Name string
	}) ([]*User, error) {
		users := make([]*User, 0, 1)
		users = append(users, &User{Id: int64(1), OrgId: int64(9086), Name: args.Name})
		return users, nil
	})

	type Admin struct {
		Id         int64
		OrgId      int64
		SuperPower string
	}
	admin := s1.Object("Admin", Admin{})
	admin.Key("id")
	admin.Federation(func(a *Admin) int64 {
		return a.Id
	})
	s1.Query().FieldFunc("admins", func(ctx context.Context) ([]*Admin, error) {
		admins := make([]*Admin, 0, 1)
		admins = append(admins, &Admin{Id: int64(1), OrgId: int64(9086), SuperPower: "flying"})
		return admins, nil
	})

	type Everyone struct {
		schemabuilder.Union
		*User
		*Admin
	}
	s1.Query().FieldFunc("everyone", func(ctx context.Context) ([]*Everyone, error) {
		everyone := make([]*Everyone, 0, 2)
		everyone = append(everyone, &Everyone{Admin: &Admin{Id: int64(1), OrgId: int64(9086), SuperPower: "flying"}})
		everyone = append(everyone, &Everyone{User: &User{Id: int64(2), OrgId: int64(9086)}})
		return everyone, nil
	})

	// The second schema has a user with contact information
	type UserWithContactInfo struct {
		Id          int64
		OrgId       int64
		Email       string
		PhoneNumber string
	}
	s2 := schemabuilder.NewSchema()
	s2.Federation().FieldFunc("User", func(args struct{ Keys []int64 }) []*UserWithContactInfo {
		users := make([]*UserWithContactInfo, 0, len(args.Keys))
		users = append(users, &UserWithContactInfo{Id: int64(1), Email: "yaaayeeeet@gmail.com", PhoneNumber: "555"})
		return users
	})
	s2.Query().FieldFunc("secretUsers", func(ctx context.Context) ([]*UserWithContactInfo, error) {
		users := make([]*UserWithContactInfo, 0, 1)
		users = append(users, &UserWithContactInfo{Id: int64(1), OrgId: int64(1), Email: "test@gmail.com", PhoneNumber: "555"})
		return users, nil
	})

	user2 := s2.Object("User", UserWithContactInfo{})
	user2.Key("id")
	user2.FieldFunc("secret", func(ctx context.Context, user *UserWithContactInfo) (string, error) {
		return "shhhhh", nil
	})

	ctx := context.Background()
	execs, err := makeExecutors(map[string]*schemabuilder.Schema{
		"s1": s1,
		"s2": s2,
	})
	if err != nil {
		return nil, nil, nil, err
	}

	e, err := NewExecutor(ctx, execs)
	return e, s1, s2, err
}

func getExpectedSchemaWithFederationInfo(t *testing.T, s1 *schemabuilder.Schema, s2 *schemabuilder.Schema) *SchemaWithFederationInfo {
	introspectionQueryReasult1 := extractSchema(t, s1.MustBuild())
	introspectionQueryReasult2 := extractSchema(t, s2.MustBuild())

	schemas := make(map[string]*introspectionQueryResult)
	schemas["s1"] = introspectionQueryReasult1
	schemas["s2"] = introspectionQueryReasult2

	// Add introspection schema for federeated client
	schemaWithFederationInfo, err := convertSchema(schemas)
	require.NoError(t, err)
	introspectionSchema := introspection.BareIntrospectionSchema(schemaWithFederationInfo.Schema)
	introspectionServer := &Server{schema: introspectionSchema}
	schemaWithIntrospection, err := introspection.RunIntrospectionQuery(introspection.BareIntrospectionSchema(introspectionServer.schema))
	require.NoError(t, err)
	var iq introspectionQueryResult
	err = json.Unmarshal(schemaWithIntrospection, &iq)
	require.NoError(t, err)
	schemas["introspection"] = &iq

	// Fetch federated schema from introspection query results
	schemaWithFederationInfo, err = convertSchema(schemas)
	require.NoError(t, err)
	return schemaWithFederationInfo
}

func TestMultipleExecutorGeneratedSchemas(t *testing.T) {
	e, s1, s2, err := createExecutorWithFederatedObjects()
	require.NoError(t, err)
	expectedSchemaWithFederationInfo := getExpectedSchemaWithFederationInfo(t, s1, s2)
	assert.Equal(t, getFieldServiceMaps(t, e.planner.schema), getFieldServiceMaps(t, expectedSchemaWithFederationInfo))
}

func runAndValidateQueryResults(t *testing.T, ctx context.Context, e *Executor, query string, out string) {
	res, err := e.Execute(ctx, graphql.MustParse(query, map[string]interface{}{}))
	var expected interface{}
	err = json.Unmarshal([]byte(out), &expected)
	require.NoError(t, err)
	assert.Equal(t, expected, res)
}

func runAndValidateQueryError(t *testing.T, ctx context.Context, e *Executor, query string, out string, expectedError string) {
	_, err := e.Execute(ctx, graphql.MustParse(query, map[string]interface{}{}))
	assert.True(t, strings.Contains(err.Error(), expectedError))
}

func TestExecutorQueriesFieldsOnOneService(t *testing.T) {
	e, _, _, err := createExecutorWithFederatedObjects()
	require.NoError(t, err)
	testCases := []struct {
		Name   string
		Query  string
		Output string
	}{
		{
			Name: "query fields on schema s1",
			Query: `
				query Foo {
					users {
						id
					}
				}`,
			Output: `
				{
					"users":[
						{
							"__key":1,
							"id":1
						}
					]
				}`,
		},
		{
			Name: "query fields on schema s2",
			Query: `
				query Foo {
					secretUsers {
						id
						secret
					}
				}`,
			Output: `
				{
					"secretUsers":[
						{
							"__key":1,
							"id":1,
							"secret":"shhhhh"
						}
					]
				}`,
		},
		{
			Name: "query fields on schema s1 and s2",
			Query: `
				query Foo {
					admins {
						superPower
					}
					secretUsers {
						id
					}
				}`,
			Output: `
				{
					"admins":[
						{
							"__key":1,
							"superPower":"flying"
						}
					],
					"secretUsers":[
						{
							"__key":1,
							"id":1
						}
					]
				}`,
		},
		{
			Name: "multiple query fields on schema s1",
			Query: `
				query Foo {
					admins {
						superPower
					}
					users {
						id
					}
				}`,
			Output: `
				{
					"admins":[
						{
							"__key":1,
							"superPower":"flying"
						}
					],
					"users":[
						{
							"__key":1,
							"id":1
						}
					]
				}`,
		},
	}
	for _, testCase := range testCases {
		t.Run(testCase.Name, func(t *testing.T) {
			// Validates that we were able to execute the query on multiple
			// schemas and correctly stitch the results back together
			ctx := context.Background()
			runAndValidateQueryResults(t, ctx, e, testCase.Query, testCase.Output)
		})
	}
}

func TestExecutorQueriesFieldsOnOneServiceWithArgs(t *testing.T) {
	e, _, _, err := createExecutorWithFederatedObjects()
	require.NoError(t, err)
	testCases := []struct {
		Name          string
		Query         string
		Output        string
		Error         bool
		ExpectedError string
	}{
		{
			Name: "query fields with args",
			Query: `
				query Foo {
					usersWithArgs(name: "foo") {
						id
						name
					}
				}`,
			Output: `
			{
				"usersWithArgs":[
					{
						"__key":1,
						"id":1,
						"name":"foo"
					}
				]
			}`,
			Error: false,
		},
		{
			Name: "query without necessary arguments",
			Query: `
				query Foo {
					usersWithArgs(foo: "foo") {
						id
						name
					}
				}`,
			Output:        "",
			Error:         true,
			ExpectedError: "error parsing args for \"usersWithArgs\": name: not a string",
		},
		{
			Name: "query without necessary arguments 2",
			Query: `
				query Foo {
					usersWithArgs {
						id
						name
					}
				}`,
			Output:        "",
			Error:         true,
			ExpectedError: "error parsing args for \"usersWithArgs\": name: not a string",
		},
	}
	for _, testCase := range testCases {
		t.Run(testCase.Name, func(t *testing.T) {
			ctx := context.Background()
			if !testCase.Error {
				// Validates that we were able to execute the query on multiple
				// schemas and correctly stitch the results back together
				runAndValidateQueryResults(t, ctx, e, testCase.Query, testCase.Output)
			} else {
				runAndValidateQueryError(t, ctx, e, testCase.Query, testCase.Output, testCase.ExpectedError)
			}

		})
	}
}

func TestExecutorQueriesFieldsOnMultipleServices(t *testing.T) {
	e, _, _, err := createExecutorWithFederatedObjects()
	require.NoError(t, err)
	testCases := []struct {
		Name          string
		Query         string
		Output        string
		Error         bool
		ExpectedError string
	}{
		{
			Name: "query fields with args",
			Query: `
			query Foo {
				users {
					id
					email
				}
			}`,
			Output: `
			{
				"users":[
					{
						"__key":1,
						"email":"yaaayeeeet@gmail.com",
						"id":1
					}
				]
			}`,
			Error: false,
		},
	}
	for _, testCase := range testCases {
		t.Run(testCase.Name, func(t *testing.T) {
			ctx := context.Background()
			if !testCase.Error {
				// Validates that we were able to execute the query on multiple
				// schemas and correctly stitch the results back together
				runAndValidateQueryResults(t, ctx, e, testCase.Query, testCase.Output)
			} else {
				runAndValidateQueryError(t, ctx, e, testCase.Query, testCase.Output, testCase.ExpectedError)
			}

		})
	}
}
<commit_msg>federation: executor test for union types<commit_after>package federation

import (
	"context"
	"encoding/json"
	"strings"
	"testing"

	"github.com/samsarahq/thunder/graphql"
	"github.com/samsarahq/thunder/graphql/introspection"
	"github.com/samsarahq/thunder/graphql/schemabuilder"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func makeExecutors(schemas map[string]*schemabuilder.Schema) (map[string]ExecutorClient, error) {
	executors := make(map[string]ExecutorClient)

	for name, schema := range schemas {
		srv, err := NewServer(schema.MustBuild())
		if err != nil {
			return nil, err
		}
		executors[name] = &DirectExecutorClient{Client: srv}
	}

	return executors, nil
}

func createExecutor() (*Executor, error) {
	e, _, _, _, err := createExecutorWithFederatedObjects()
	return e, err
}
func createExecutorWithFederatedObjects() (*Executor, *schemabuilder.Schema, *schemabuilder.Schema, *schemabuilder.Schema, error) {
	// The first schema has a user object with an id and orgId
	type User struct {
		Id    int64
		OrgId int64
		Name  string
	}
	s1 := schemabuilder.NewSchema()
	user := s1.Object("User", User{})
	user.Key("id")
	user.Federation(func(u *User) int64 {
		return u.Id
	})
	s1.Query().FieldFunc("users", func(ctx context.Context) ([]*User, error) {
		users := make([]*User, 0, 1)
		users = append(users, &User{Id: int64(1), OrgId: int64(9086)})
		return users, nil
	})

	s1.Query().FieldFunc("usersWithArgs", func(args struct {
		Name string
	}) ([]*User, error) {
		users := make([]*User, 0, 1)
		users = append(users, &User{Id: int64(1), OrgId: int64(9086), Name: args.Name})
		return users, nil
	})

	type Admin struct {
		Id         int64
		OrgId      int64
		SuperPower string
	}
	admin := s1.Object("Admin", Admin{})
	admin.Key("id")
	admin.Federation(func(a *Admin) int64 {
		return a.Id
	})
	s1.Query().FieldFunc("admins", func(ctx context.Context) ([]*Admin, error) {
		admins := make([]*Admin, 0, 1)
		admins = append(admins, &Admin{Id: int64(1), OrgId: int64(9086), SuperPower: "flying"})
		return admins, nil
	})

	type Everyone struct {
		schemabuilder.Union
		*User
		*Admin
	}
	s1.Query().FieldFunc("everyone", func(ctx context.Context) ([]*Everyone, error) {
		everyone := make([]*Everyone, 0, 2)
		everyone = append(everyone, &Everyone{Admin: &Admin{Id: int64(1), OrgId: int64(9086), SuperPower: "flying"}})
		everyone = append(everyone, &Everyone{User: &User{Id: int64(2), OrgId: int64(9086)}})
		return everyone, nil
	})

	// The second schema has a user with contact information
	type UserWithContactInfo struct {
		Id          int64
		OrgId       int64
		Email       string
		PhoneNumber string
	}
	s2 := schemabuilder.NewSchema()
	s2.Federation().FieldFunc("User", func(args struct{ Keys []int64 }) []*UserWithContactInfo {
		users := make([]*UserWithContactInfo, 0, len(args.Keys))
		for _, key := range args.Keys {
			users = append(users, &UserWithContactInfo{Id: key, Email: "yaaayeeeet@gmail.com", PhoneNumber: "555"})
		}
		return users
	})
	s2.Query().FieldFunc("secretUsers", func(ctx context.Context) ([]*UserWithContactInfo, error) {
		users := make([]*UserWithContactInfo, 0, 1)
		users = append(users, &UserWithContactInfo{Id: int64(1), OrgId: int64(1), Email: "test@gmail.com", PhoneNumber: "555"})
		return users, nil
	})

	user2 := s2.Object("User", UserWithContactInfo{})
	user2.Key("id")
	user2.FieldFunc("secret", func(ctx context.Context, user *UserWithContactInfo) (string, error) {
		return "shhhhh", nil
	})

	s2.Federation().FieldFunc("Admin", func(args struct{ Keys []int64 }) []*Admin {
		admins := make([]*Admin, 0, len(args.Keys))
		for _, key := range args.Keys {
			admins = append(admins, &Admin{Id: key, SuperPower: "flying"})
		}
		return admins
	})
	admin2 := s2.Object("Admin", Admin{})
	admin2.Key("id")
	admin2.FieldFunc("hiding", func(ctx context.Context, user *Admin) (bool, error) {
		return true, nil
	})

	type Driver struct {
		Id   int64
		Name string
	}
	driver := s1.Object("Driver", Driver{})
	driver.Key("id")
	driver.Federation(func(d *Driver) int64 {
		return d.Id
	})
	user.FieldFunc("driver", func(ctx context.Context, user *User) (*Driver, error) {
		return &Driver{Id: int64(1), Name: "bob"}, nil
	})

	s3 := schemabuilder.NewSchema()
	s3.Federation().FieldFunc("Driver", func(args struct{ Keys []int64 }) []*Driver {
		drivers := make([]*Driver, 0, len(args.Keys))
		for _, key := range args.Keys {
			drivers = append(drivers, &Driver{Id: key, Name: "bob"})
		}
		return drivers
	})
	driver3 := s3.Object("Driver", Driver{})
	driver3.Key("id")
	driver3.FieldFunc("isDriving", func(ctx context.Context, driver *Driver) (bool, error) {
		return true, nil
	})

	ctx := context.Background()
	execs, err := makeExecutors(map[string]*schemabuilder.Schema{
		"s1": s1,
		"s2": s2,
		"s3": s3,
	})
	if err != nil {
		return nil, nil, nil, nil, err
	}

	e, err := NewExecutor(ctx, execs)
	return e, s1, s2, s3, err
}

func getExpectedSchemaWithFederationInfo(t *testing.T, s1 *schemabuilder.Schema, s2 *schemabuilder.Schema, s3 *schemabuilder.Schema) *SchemaWithFederationInfo {
	introspectionQueryResult1 := extractSchema(t, s1.MustBuild())
	introspectionQueryResult2 := extractSchema(t, s2.MustBuild())
	introspectionQueryResult3 := extractSchema(t, s3.MustBuild())

	schemas := make(map[string]*introspectionQueryResult)
	schemas["s1"] = introspectionQueryResult1
	schemas["s2"] = introspectionQueryResult2
	schemas["s3"] = introspectionQueryResult3
	// Add introspection schema for federeated client
	schemaWithFederationInfo, err := convertSchema(schemas)
	require.NoError(t, err)
	introspectionSchema := introspection.BareIntrospectionSchema(schemaWithFederationInfo.Schema)
	introspectionServer := &Server{schema: introspectionSchema}
	schemaWithIntrospection, err := introspection.RunIntrospectionQuery(introspection.BareIntrospectionSchema(introspectionServer.schema))
	require.NoError(t, err)
	var iq introspectionQueryResult
	err = json.Unmarshal(schemaWithIntrospection, &iq)
	require.NoError(t, err)
	schemas["introspection"] = &iq

	// Fetch federated schema from introspection query results
	schemaWithFederationInfo, err = convertSchema(schemas)
	require.NoError(t, err)
	return schemaWithFederationInfo
}

func TestMultipleExecutorGeneratedSchemas(t *testing.T) {
	e, s1, s2, s3, err := createExecutorWithFederatedObjects()
	require.NoError(t, err)
	expectedSchemaWithFederationInfo := getExpectedSchemaWithFederationInfo(t, s1, s2, s3)
	assert.Equal(t, getFieldServiceMaps(t, e.planner.schema), getFieldServiceMaps(t, expectedSchemaWithFederationInfo))
}

func runAndValidateQueryResults(t *testing.T, ctx context.Context, e *Executor, query string, out string) {
	res, err := e.Execute(ctx, graphql.MustParse(query, map[string]interface{}{}))
	var expected interface{}
	err = json.Unmarshal([]byte(out), &expected)
	require.NoError(t, err)
	assert.Equal(t, expected, res)
}

func runAndValidateQueryError(t *testing.T, ctx context.Context, e *Executor, query string, out string, expectedError string) {
	_, err := e.Execute(ctx, graphql.MustParse(query, map[string]interface{}{}))
	assert.True(t, strings.Contains(err.Error(), expectedError))
}

func TestExecutorQueriesFieldsOnOneService(t *testing.T) {
	e, err := createExecutor()
	require.NoError(t, err)
	testCases := []struct {
		Name   string
		Query  string
		Output string
	}{
		{
			Name: "query fields on schema s1",
			Query: `
				query Foo {
					users {
						id
					}
				}`,
			Output: `
				{
					"users":[
						{
							"__key":1,
							"id":1
						}
					]
				}`,
		},
		{
			Name: "query fields on schema s2",
			Query: `
				query Foo {
					secretUsers {
						id
						secret
					}
				}`,
			Output: `
				{
					"secretUsers":[
						{
							"__key":1,
							"id":1,
							"secret":"shhhhh"
						}
					]
				}`,
		},
		{
			Name: "query fields on schema s1 and s2",
			Query: `
				query Foo {
					admins {
						superPower
					}
					secretUsers {
						id
					}
				}`,
			Output: `
				{
					"admins":[
						{
							"__key":1,
							"superPower":"flying"
						}
					],
					"secretUsers":[
						{
							"__key":1,
							"id":1
						}
					]
				}`,
		},
		{
			Name: "multiple query fields on schema s1",
			Query: `
				query Foo {
					admins {
						superPower
					}
					users {
						id
					}
				}`,
			Output: `
				{
					"admins":[
						{
							"__key":1,
							"superPower":"flying"
						}
					],
					"users":[
						{
							"__key":1,
							"id":1
						}
					]
				}`,
		},
	}
	for _, testCase := range testCases {
		t.Run(testCase.Name, func(t *testing.T) {
			// Validates that we were able to execute the query on multiple
			// schemas and correctly stitch the results back together
			ctx := context.Background()
			runAndValidateQueryResults(t, ctx, e, testCase.Query, testCase.Output)
		})
	}
}

func TestExecutorQueriesFieldsOnOneServiceWithArgs(t *testing.T) {
	e, err := createExecutor()
	require.NoError(t, err)
	testCases := []struct {
		Name          string
		Query         string
		Output        string
		Error         bool
		ExpectedError string
	}{
		{
			Name: "query fields with args",
			Query: `
				query Foo {
					usersWithArgs(name: "foo") {
						id
						name
					}
				}`,
			Output: `
			{
				"usersWithArgs":[
					{
						"__key":1,
						"id":1,
						"name":"foo"
					}
				]
			}`,
			Error: false,
		},
		{
			Name: "query without necessary arguments",
			Query: `
				query Foo {
					usersWithArgs(foo: "foo") {
						id
						name
					}
				}`,
			Output:        "",
			Error:         true,
			ExpectedError: "error parsing args for \"usersWithArgs\": name: not a string",
		},
		{
			Name: "query without necessary arguments 2",
			Query: `
				query Foo {
					usersWithArgs {
						id
						name
					}
				}`,
			Output:        "",
			Error:         true,
			ExpectedError: "error parsing args for \"usersWithArgs\": name: not a string",
		},
	}
	for _, testCase := range testCases {
		t.Run(testCase.Name, func(t *testing.T) {
			ctx := context.Background()
			if !testCase.Error {
				// Validates that we were able to execute the query on multiple
				// schemas and correctly stitch the results back together
				runAndValidateQueryResults(t, ctx, e, testCase.Query, testCase.Output)
			} else {
				runAndValidateQueryError(t, ctx, e, testCase.Query, testCase.Output, testCase.ExpectedError)
			}

		})
	}
}

func TestExecutorQueriesFieldsOnMultipleServices(t *testing.T) {
	e, err := createExecutor()
	require.NoError(t, err)
	testCases := []struct {
		Name          string
		Query         string
		Output        string
		Error         bool
		ExpectedError string
	}{
		{
			Name: "query fields with args",
			Query: `
			query Foo {
				users {
					id
					email
				}
			}`,
			Output: `
			{
				"users":[
					{
						"__key":1,
						"email":"yaaayeeeet@gmail.com",
						"id":1
					}
				]
			}`,
			Error: false,
		},
	}
	for _, testCase := range testCases {
		t.Run(testCase.Name, func(t *testing.T) {
			ctx := context.Background()
			if !testCase.Error {
				// Validates that we were able to execute the query on multiple
				// schemas and correctly stitch the results back together
				runAndValidateQueryResults(t, ctx, e, testCase.Query, testCase.Output)
			} else {
				runAndValidateQueryError(t, ctx, e, testCase.Query, testCase.Output, testCase.ExpectedError)
			}

		})
	}
}

func TestExecutorQueriesFieldsOnUnionTypes(t *testing.T) {
	e, err := createExecutor()
	require.NoError(t, err)
	testCases := []struct {
		Name          string
		Query         string
		Output        string
		Error         bool
		ExpectedError string
	}{
		{
			Name: "query fields with union type, admin and user, 2 server hops",
			Query: `
			query Foo {
				everyone {
					... on Admin {
						id
						hiding
						superPower

					}
					... on User {
						id
						email
					}
				}
			}`,
			Output: `
			{
				"everyone":[
					{
						"__key":1,
						"__typename":"Admin",
						"id":1,
						"hiding":true,
						"superPower":"flying"
					},
					{
						"__key":2,
						"__typename":"User",
						"id":2,
						"email":"yaaayeeeet@gmail.com"
					}
				]
			}`,
			Error: false,
		},
		{
			Name: "query fields with union type with nested object",
			Query: `
			query Foo {
				everyone {
					... on User {
						id
						driver {
							id
							isDriving
						}
					}
					... on Admin {
						id
					}
				}
			}`,
			Output: `
			{
				"everyone":[
					{
						"__key":1,
						"__typename":"Admin",
						"id":1
					},
					{
						"__key":2,
						"__typename":"User",
						"id":2,
						"driver": {
							"id":1,
							"__key":1,
							"isDriving":true
						}
					}
				]
			}`,
			Error: false,
		},
		{
			Name: "query fields with union type for admin and user, 1 schema hop",
			Query: `
			query Foo {
				everyone {
					... on Admin {
						id
						hiding
					}
					... on User {
						id
					}
				}
			}`,
			Output: `
			{
				"everyone":[
					{
						"__key":1,
						"__typename":"Admin",
						"id":1,
						"hiding":true
					},
					{
						"__key":2,
						"__typename":"User",
						"id":2
					}
				]
			}`,
			Error: false,
		},
	}
	for _, testCase := range testCases {
		t.Run(testCase.Name, func(t *testing.T) {
			ctx := context.Background()
			if !testCase.Error {
				// Validates that we were able to execute the query on multiple
				// schemas and correctly stitch the results back together
				runAndValidateQueryResults(t, ctx, e, testCase.Query, testCase.Output)
			} else {
				runAndValidateQueryError(t, ctx, e, testCase.Query, testCase.Output, testCase.ExpectedError)
			}

		})
	}
}
<|endoftext|>


<commit_before>package terraform

import (
	"fmt"
	"log"

	"github.com/hashicorp/terraform/internal/plans"
	"github.com/hashicorp/terraform/internal/tfdiags"

	"github.com/hashicorp/terraform/internal/addrs"
	"github.com/hashicorp/terraform/internal/configs"
	"github.com/hashicorp/terraform/internal/states"
)

// NodeDestroyResourceInstance represents a resource instance that is to be
// destroyed.
type NodeDestroyResourceInstance struct {
	*NodeAbstractResourceInstance

	// If DeposedKey is set to anything other than states.NotDeposed then
	// this node destroys a deposed object of the associated instance
	// rather than its current object.
	DeposedKey states.DeposedKey
}

var (
	_ GraphNodeModuleInstance      = (*NodeDestroyResourceInstance)(nil)
	_ GraphNodeConfigResource      = (*NodeDestroyResourceInstance)(nil)
	_ GraphNodeResourceInstance    = (*NodeDestroyResourceInstance)(nil)
	_ GraphNodeDestroyer           = (*NodeDestroyResourceInstance)(nil)
	_ GraphNodeDestroyerCBD        = (*NodeDestroyResourceInstance)(nil)
	_ GraphNodeReferenceable       = (*NodeDestroyResourceInstance)(nil)
	_ GraphNodeReferencer          = (*NodeDestroyResourceInstance)(nil)
	_ GraphNodeExecutable          = (*NodeDestroyResourceInstance)(nil)
	_ GraphNodeProviderConsumer    = (*NodeDestroyResourceInstance)(nil)
	_ GraphNodeProvisionerConsumer = (*NodeDestroyResourceInstance)(nil)
)

func (n *NodeDestroyResourceInstance) Name() string {
	if n.DeposedKey != states.NotDeposed {
		return fmt.Sprintf("%s (destroy deposed %s)", n.ResourceInstanceAddr(), n.DeposedKey)
	}
	return n.ResourceInstanceAddr().String() + " (destroy)"
}

func (n *NodeDestroyResourceInstance) ProvidedBy() (addr addrs.ProviderConfig, exact bool) {
	if n.Addr.Resource.Resource.Mode == addrs.DataResourceMode {
		// indicate that this node does not require a configured provider
		return nil, true
	}
	return n.NodeAbstractResourceInstance.ProvidedBy()
}

// GraphNodeDestroyer
func (n *NodeDestroyResourceInstance) DestroyAddr() *addrs.AbsResourceInstance {
	addr := n.ResourceInstanceAddr()
	return &addr
}

// GraphNodeDestroyerCBD
func (n *NodeDestroyResourceInstance) CreateBeforeDestroy() bool {
	// State takes precedence during destroy.
	// If the resource was removed, there is no config to check.
	// If CBD was forced from descendent, it should be saved in the state
	// already.
	if s := n.instanceState; s != nil {
		if s.Current != nil {
			return s.Current.CreateBeforeDestroy
		}
	}

	if n.Config != nil && n.Config.Managed != nil {
		return n.Config.Managed.CreateBeforeDestroy
	}

	return false
}

// GraphNodeDestroyerCBD
func (n *NodeDestroyResourceInstance) ModifyCreateBeforeDestroy(v bool) error {
	return nil
}

// GraphNodeReferenceable, overriding NodeAbstractResource
func (n *NodeDestroyResourceInstance) ReferenceableAddrs() []addrs.Referenceable {
	normalAddrs := n.NodeAbstractResourceInstance.ReferenceableAddrs()
	destroyAddrs := make([]addrs.Referenceable, len(normalAddrs))

	phaseType := addrs.ResourceInstancePhaseDestroy
	if n.CreateBeforeDestroy() {
		phaseType = addrs.ResourceInstancePhaseDestroyCBD
	}

	for i, normalAddr := range normalAddrs {
		switch ta := normalAddr.(type) {
		case addrs.Resource:
			destroyAddrs[i] = ta.Phase(phaseType)
		case addrs.ResourceInstance:
			destroyAddrs[i] = ta.Phase(phaseType)
		default:
			destroyAddrs[i] = normalAddr
		}
	}

	return destroyAddrs
}

// GraphNodeReferencer, overriding NodeAbstractResource
func (n *NodeDestroyResourceInstance) References() []*addrs.Reference {
	// If we have a config, then we need to include destroy-time dependencies
	if c := n.Config; c != nil && c.Managed != nil {
		var result []*addrs.Reference

		// We include conn info and config for destroy time provisioners
		// as dependencies that we have.
		for _, p := range c.Managed.Provisioners {
			schema := n.ProvisionerSchemas[p.Type]

			if p.When == configs.ProvisionerWhenDestroy {
				if p.Connection != nil {
					result = append(result, ReferencesFromConfig(p.Connection.Config, connectionBlockSupersetSchema)...)
				}
				result = append(result, ReferencesFromConfig(p.Config, schema)...)
			}
		}

		return result
	}

	return nil
}

// GraphNodeExecutable
func (n *NodeDestroyResourceInstance) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
	addr := n.ResourceInstanceAddr()

	// Eval info is different depending on what kind of resource this is
	switch addr.Resource.Resource.Mode {
	case addrs.ManagedResourceMode:
		return n.managedResourceExecute(ctx)
	case addrs.DataResourceMode:
		return n.dataResourceExecute(ctx)
	default:
		panic(fmt.Errorf("unsupported resource mode %s", n.Config.Mode))
	}
}

func (n *NodeDestroyResourceInstance) managedResourceExecute(ctx EvalContext) (diags tfdiags.Diagnostics) {
	addr := n.ResourceInstanceAddr()

	// Get our state
	is := n.instanceState
	if is == nil {
		log.Printf("[WARN] NodeDestroyResourceInstance for %s with no state", addr)
	}

	// These vars are updated through pointers at various stages below.
	var changeApply *plans.ResourceInstanceChange
	var state *states.ResourceInstanceObject

	_, providerSchema, err := getProvider(ctx, n.ResolvedProvider)
	diags = diags.Append(err)
	if diags.HasErrors() {
		return diags
	}

	changeApply, err = n.readDiff(ctx, providerSchema)
	diags = diags.Append(err)
	if diags.HasErrors() {
		return diags
	}

	changeApply = reducePlan(addr.Resource, changeApply, true)
	// reducePlan may have simplified our planned change
	// into a NoOp if it does not require destroying.
	if changeApply == nil || changeApply.Action == plans.NoOp {
		return diags
	}

	state, readDiags := n.readResourceInstanceState(ctx, addr)
	diags = diags.Append(readDiags)
	if diags.HasErrors() {
		return diags
	}

	// Exit early if the state object is null after reading the state
	if state == nil || state.Value.IsNull() {
		return diags
	}

	diags = diags.Append(n.preApplyHook(ctx, changeApply))
	if diags.HasErrors() {
		return diags
	}

	// Run destroy provisioners if not tainted
	if state.Status != states.ObjectTainted {
		applyProvisionersDiags := n.evalApplyProvisioners(ctx, state, false, configs.ProvisionerWhenDestroy)
		diags = diags.Append(applyProvisionersDiags)
		// keep the diags separate from the main set until we handle the cleanup

		if diags.HasErrors() {
			// If we have a provisioning error, then we just call
			// the post-apply hook now.
			diags = diags.Append(n.postApplyHook(ctx, state, diags.Err()))
			return diags
		}
	}

	// Managed resources need to be destroyed, while data sources
	// are only removed from state.
	// we pass a nil configuration to apply because we are destroying
	s, d := n.apply(ctx, state, changeApply, nil, false)
	state, diags = s, diags.Append(d)
	// we don't return immediately here on error, so that the state can be
	// finalized

	err = n.writeResourceInstanceState(ctx, state, workingState)
	if err != nil {
		return diags.Append(err)
	}

	// create the err value for postApplyHook
	diags = diags.Append(n.postApplyHook(ctx, state, diags.Err()))
	diags = diags.Append(updateStateHook(ctx))
	return diags
}

func (n *NodeDestroyResourceInstance) dataResourceExecute(ctx EvalContext) (diags tfdiags.Diagnostics) {
	log.Printf("[TRACE] NodeDestroyResourceInstance: removing state object for %s", n.Addr)
	ctx.State().SetResourceInstanceCurrent(n.Addr, nil, n.ResolvedProvider)
	return diags.Append(updateStateHook(ctx))
}
<commit_msg>Check for nil change during apply<commit_after>package terraform

import (
	"fmt"
	"log"

	"github.com/hashicorp/terraform/internal/plans"
	"github.com/hashicorp/terraform/internal/tfdiags"

	"github.com/hashicorp/terraform/internal/addrs"
	"github.com/hashicorp/terraform/internal/configs"
	"github.com/hashicorp/terraform/internal/states"
)

// NodeDestroyResourceInstance represents a resource instance that is to be
// destroyed.
type NodeDestroyResourceInstance struct {
	*NodeAbstractResourceInstance

	// If DeposedKey is set to anything other than states.NotDeposed then
	// this node destroys a deposed object of the associated instance
	// rather than its current object.
	DeposedKey states.DeposedKey
}

var (
	_ GraphNodeModuleInstance      = (*NodeDestroyResourceInstance)(nil)
	_ GraphNodeConfigResource      = (*NodeDestroyResourceInstance)(nil)
	_ GraphNodeResourceInstance    = (*NodeDestroyResourceInstance)(nil)
	_ GraphNodeDestroyer           = (*NodeDestroyResourceInstance)(nil)
	_ GraphNodeDestroyerCBD        = (*NodeDestroyResourceInstance)(nil)
	_ GraphNodeReferenceable       = (*NodeDestroyResourceInstance)(nil)
	_ GraphNodeReferencer          = (*NodeDestroyResourceInstance)(nil)
	_ GraphNodeExecutable          = (*NodeDestroyResourceInstance)(nil)
	_ GraphNodeProviderConsumer    = (*NodeDestroyResourceInstance)(nil)
	_ GraphNodeProvisionerConsumer = (*NodeDestroyResourceInstance)(nil)
)

func (n *NodeDestroyResourceInstance) Name() string {
	if n.DeposedKey != states.NotDeposed {
		return fmt.Sprintf("%s (destroy deposed %s)", n.ResourceInstanceAddr(), n.DeposedKey)
	}
	return n.ResourceInstanceAddr().String() + " (destroy)"
}

func (n *NodeDestroyResourceInstance) ProvidedBy() (addr addrs.ProviderConfig, exact bool) {
	if n.Addr.Resource.Resource.Mode == addrs.DataResourceMode {
		// indicate that this node does not require a configured provider
		return nil, true
	}
	return n.NodeAbstractResourceInstance.ProvidedBy()
}

// GraphNodeDestroyer
func (n *NodeDestroyResourceInstance) DestroyAddr() *addrs.AbsResourceInstance {
	addr := n.ResourceInstanceAddr()
	return &addr
}

// GraphNodeDestroyerCBD
func (n *NodeDestroyResourceInstance) CreateBeforeDestroy() bool {
	// State takes precedence during destroy.
	// If the resource was removed, there is no config to check.
	// If CBD was forced from descendent, it should be saved in the state
	// already.
	if s := n.instanceState; s != nil {
		if s.Current != nil {
			return s.Current.CreateBeforeDestroy
		}
	}

	if n.Config != nil && n.Config.Managed != nil {
		return n.Config.Managed.CreateBeforeDestroy
	}

	return false
}

// GraphNodeDestroyerCBD
func (n *NodeDestroyResourceInstance) ModifyCreateBeforeDestroy(v bool) error {
	return nil
}

// GraphNodeReferenceable, overriding NodeAbstractResource
func (n *NodeDestroyResourceInstance) ReferenceableAddrs() []addrs.Referenceable {
	normalAddrs := n.NodeAbstractResourceInstance.ReferenceableAddrs()
	destroyAddrs := make([]addrs.Referenceable, len(normalAddrs))

	phaseType := addrs.ResourceInstancePhaseDestroy
	if n.CreateBeforeDestroy() {
		phaseType = addrs.ResourceInstancePhaseDestroyCBD
	}

	for i, normalAddr := range normalAddrs {
		switch ta := normalAddr.(type) {
		case addrs.Resource:
			destroyAddrs[i] = ta.Phase(phaseType)
		case addrs.ResourceInstance:
			destroyAddrs[i] = ta.Phase(phaseType)
		default:
			destroyAddrs[i] = normalAddr
		}
	}

	return destroyAddrs
}

// GraphNodeReferencer, overriding NodeAbstractResource
func (n *NodeDestroyResourceInstance) References() []*addrs.Reference {
	// If we have a config, then we need to include destroy-time dependencies
	if c := n.Config; c != nil && c.Managed != nil {
		var result []*addrs.Reference

		// We include conn info and config for destroy time provisioners
		// as dependencies that we have.
		for _, p := range c.Managed.Provisioners {
			schema := n.ProvisionerSchemas[p.Type]

			if p.When == configs.ProvisionerWhenDestroy {
				if p.Connection != nil {
					result = append(result, ReferencesFromConfig(p.Connection.Config, connectionBlockSupersetSchema)...)
				}
				result = append(result, ReferencesFromConfig(p.Config, schema)...)
			}
		}

		return result
	}

	return nil
}

// GraphNodeExecutable
func (n *NodeDestroyResourceInstance) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
	addr := n.ResourceInstanceAddr()

	// Eval info is different depending on what kind of resource this is
	switch addr.Resource.Resource.Mode {
	case addrs.ManagedResourceMode:
		return n.managedResourceExecute(ctx)
	case addrs.DataResourceMode:
		return n.dataResourceExecute(ctx)
	default:
		panic(fmt.Errorf("unsupported resource mode %s", n.Config.Mode))
	}
}

func (n *NodeDestroyResourceInstance) managedResourceExecute(ctx EvalContext) (diags tfdiags.Diagnostics) {
	addr := n.ResourceInstanceAddr()

	// Get our state
	is := n.instanceState
	if is == nil {
		log.Printf("[WARN] NodeDestroyResourceInstance for %s with no state", addr)
	}

	// These vars are updated through pointers at various stages below.
	var changeApply *plans.ResourceInstanceChange
	var state *states.ResourceInstanceObject

	_, providerSchema, err := getProvider(ctx, n.ResolvedProvider)
	diags = diags.Append(err)
	if diags.HasErrors() {
		return diags
	}

	changeApply, err = n.readDiff(ctx, providerSchema)
	diags = diags.Append(err)
	if changeApply == nil || diags.HasErrors() {
		return diags
	}

	changeApply = reducePlan(addr.Resource, changeApply, true)
	// reducePlan may have simplified our planned change
	// into a NoOp if it does not require destroying.
	if changeApply == nil || changeApply.Action == plans.NoOp {
		return diags
	}

	state, readDiags := n.readResourceInstanceState(ctx, addr)
	diags = diags.Append(readDiags)
	if diags.HasErrors() {
		return diags
	}

	// Exit early if the state object is null after reading the state
	if state == nil || state.Value.IsNull() {
		return diags
	}

	diags = diags.Append(n.preApplyHook(ctx, changeApply))
	if diags.HasErrors() {
		return diags
	}

	// Run destroy provisioners if not tainted
	if state.Status != states.ObjectTainted {
		applyProvisionersDiags := n.evalApplyProvisioners(ctx, state, false, configs.ProvisionerWhenDestroy)
		diags = diags.Append(applyProvisionersDiags)
		// keep the diags separate from the main set until we handle the cleanup

		if diags.HasErrors() {
			// If we have a provisioning error, then we just call
			// the post-apply hook now.
			diags = diags.Append(n.postApplyHook(ctx, state, diags.Err()))
			return diags
		}
	}

	// Managed resources need to be destroyed, while data sources
	// are only removed from state.
	// we pass a nil configuration to apply because we are destroying
	s, d := n.apply(ctx, state, changeApply, nil, false)
	state, diags = s, diags.Append(d)
	// we don't return immediately here on error, so that the state can be
	// finalized

	err = n.writeResourceInstanceState(ctx, state, workingState)
	if err != nil {
		return diags.Append(err)
	}

	// create the err value for postApplyHook
	diags = diags.Append(n.postApplyHook(ctx, state, diags.Err()))
	diags = diags.Append(updateStateHook(ctx))
	return diags
}

func (n *NodeDestroyResourceInstance) dataResourceExecute(ctx EvalContext) (diags tfdiags.Diagnostics) {
	log.Printf("[TRACE] NodeDestroyResourceInstance: removing state object for %s", n.Addr)
	ctx.State().SetResourceInstanceCurrent(n.Addr, nil, n.ResolvedProvider)
	return diags.Append(updateStateHook(ctx))
}
<|endoftext|>


<commit_before>package insunit

import (
	"github.com/yofu/dxf/format"
)

// Unit is the drawing unit for AutoCAD DesignCenter Blocks
type Unit uint8

const (
	Unitless     Unit = 0
	Inches            = 1
	Feet              = 2
	Miles             = 3
	Millimeters       = 4
	Centimeters       = 5
	Meters            = 6
	Kilometers        = 7
	Microinches       = 8
	Mils              = 9
	Yards             = 10
	Angstroms         = 11
	Nanometers        = 12
	Microns           = 13
	Decimeters        = 14
	Decameters        = 15
	Hectometers       = 16
	Gigameters        = 17
	Astronomical      = 18
	LightYears        = 19
	Parsecs           = 20
)

func (u Unit) Format(f format.Formatter) {
	f.WriteInt(70, int(u))
}

func (u Unit) String() string {
	f := format.NewASCII()
	u.Format(f)
	return f.Output()
}

type Type int8

const (
	Scientific Type = iota - 1 // We want decimal to be default of zero.
	Decimal                    // This will be zero.
	Engineering
	Architectural
	Fractional
	WindowsDesktop
)

func (t Type) Format(f format.Formatter) {
	// When defining the constants we subtracted two from the values
	// to insure that Decimal was the zero value
	f.WriteInt(70, int(t+2))
}
<commit_msg>Add String methods to enums<commit_after>package insunit

import (
	"strings"

	"github.com/yofu/dxf/format"
)

// Unit is the drawing unit for AutoCAD DesignCenter Blocks
type Unit uint8

const (
	Unitless     Unit = 0
	Inches            = 1
	Feet              = 2
	Miles             = 3
	Millimeters       = 4
	Centimeters       = 5
	Meters            = 6
	Kilometers        = 7
	Microinches       = 8
	Mils              = 9
	Yards             = 10
	Angstroms         = 11
	Nanometers        = 12
	Microns           = 13
	Decimeters        = 14
	Decameters        = 15
	Hectometers       = 16
	Gigameters        = 17
	Astronomical      = 18
	LightYears        = 19
	Parsecs           = 20
)

func (u Unit) Format(f format.Formatter) {
	f.WriteInt(70, int(u))
}

func (u Unit) String() string {
	switch u {
	case Unitless:
		return "none"
	case Inches:
		return "inches"
	case Feet:
		return "feet"
	case Miles:
		return "miles"
	case Millimeters:
		return "millimeters"
	case Centimeters:
		return "centimeters"
	case Meters:
		return "meters"
	case Kilometers:
		return "kilometers"
	case Microinches:
		return "microinches"
	case Mils:
		return "mils"
	case Yards:
		return "yards"
	case Angstroms:
		return "angstroms"
	case Nanometers:
		return "nanometers"
	case Microns:
		return "microns"
	case Decimeters:
		return "decimeters"
	case Decameters:
		return "decameters"
	case Hectometers:
		return "hectometers"
	case Gigameters:
		return "gigameters"
	case Astronomical:
		return "astronomical"
	case LightYears:
		return "light years"
	case Parsecs:
		return "parsecs"
	default:
		return "unknown"
	}
}

var str2Unit = map[string]Unit{
	"none":         Unitless,
	"unitless":     Unitless,
	"inches":       Inches,
	"feet":         Feet,
	"miles":        Miles,
	"millimeters":  Millimeters,
	"centimeters":  Centimeters,
	"meters":       Meters,
	"kilometers":   Kilometers,
	"microinches":  Microinches,
	"mils":         Mils,
	"yards":        Yards,
	"angstroms":    Angstroms,
	"nanometers":   Nanometers,
	"microns":      Microns,
	"decimeters":   Decimeters,
	"decameters":   Decameters,
	"hectometers":  Hectometers,
	"gigameters":   Gigameters,
	"astronomical": Astronomical,
	"light years":  LightYears,
	"lightyears":   LightYears,
	"light-years":  LightYears,
	"parsecs":      Parsecs,
}

func UnitFromString(str string) (Unit, bool) {
	u, ok := str2Unit[strings.TrimSpace(strings.ToLower(str))]
	return u, ok
}

type Type int8

const (
	Scientific Type = iota - 1 // We want decimal to be default of zero.
	Decimal                    // This will be zero.
	Engineering
	Architectural
	Fractional
	WindowsDesktop
)

func (t Type) Format(f format.Formatter) {
	// When defining the constants we subtracted two from the values
	// to insure that Decimal was the zero value
	f.WriteInt(70, int(t+2))
}

func (t Type) String() string {
	switch t {
	case Scientific:
		return "scientific"
	case Decimal:
		return "decimal"
	case Engineering:
		return "engineering:"
	case Architectural:
		return "architectural:"
	case Fractional:
		return "fractional:"
	case WindowsDesktop:
		return "windows desktop"
	default:
		return "unknown"
	}
}

var str2Type = map[string]Type{
	"scientific":      Scientific,
	"decimal":         Decimal,
	"engineering:":    Engineering,
	"architectural:":  Architectural,
	"fractional:":     Fractional,
	"windows desktop": WindowsDesktop,
	"windowsdesktop":  WindowsDesktop,
}

func TypeFromString(str string) (Type, bool) {
	t, ok := str2Type[strings.TrimSpace(strings.ToLower(str))]
	return t, ok
}
<|endoftext|>


<commit_before>package hastads

import (
	"fmt"

	"github.com/sourcekris/goRsaTool/keys"
	"github.com/sourcekris/goRsaTool/ln"

	fmp "github.com/sourcekris/goflint"
)

// name is the name of this attack.
const name = "hastads"

// Attack implements the Hastads attack.
func Attack(ts []*keys.RSA) error {
	t := ts[0]
	if t.Key.D != nil || t.Key.PublicKey.E.Cmp(ln.BigEleven) > 0 {
		return nil
	}

	if t.CipherText == nil {
		return fmt.Errorf("%s failed - ciphertext needs to be provided for this attack", name)
	}

	c := ln.BytesToNumber(t.CipherText)
	m := new(fmp.Fmpz)
	pow := new(fmp.Fmpz)

	original := new(fmp.Fmpz).Set(c)

	for {
		m.Root(c, int32(t.Key.PublicKey.E.Int64()))
		pow.Exp(m, t.Key.PublicKey.E, t.Key.N)

		if pow.Cmp(original) == 0 {
			t.PlainText = ln.NumberToBytes(m)
			return nil
		}
		c.Add(c, t.Key.N)
	}
}
<commit_msg>add a timeout to the hastads attack<commit_after>package hastads

import (
	"context"
	"fmt"
	"log"
	"time"

	"github.com/sourcekris/goRsaTool/keys"
	"github.com/sourcekris/goRsaTool/ln"

	fmp "github.com/sourcekris/goflint"
)

// timeout puts a limit on how long fermat should attempt to find a solution.
var timeout = time.Minute * 5

// name is the name of this attack.
const name = "hastads"

func hastads(ch chan bool, n, e, c, pt *fmp.Fmpz) {
	m := new(fmp.Fmpz)
	pow := new(fmp.Fmpz)
	original := new(fmp.Fmpz).Set(c)

	for {
		m.Root(c, int32(e.Int64()))
		pow.Exp(m, e, n)

		if pow.Cmp(original) == 0 {
			pt.Set(m)
			ch <- true
		}
		c.Add(c, n)
	}
}

// Attack implements the Hastads attack.
func Attack(ts []*keys.RSA) error {
	t := ts[0]
	if t.Key.D != nil || t.Key.PublicKey.E.Cmp(ln.BigEleven) > 0 {
		return nil
	}

	if t.CipherText == nil {
		return fmt.Errorf("%s failed - ciphertext needs to be provided for this attack", name)
	}

	ctx := context.Background()
	ctx, cancel := context.WithTimeout(ctx, timeout)
	defer cancel()

	ch := make(chan bool)

	c := ln.BytesToNumber(t.CipherText)
	pt := new(fmp.Fmpz)

	if t.Verbose {
		log.Printf("%s attempt beginning with timeout %v", name, timeout)
	}
	go hastads(ch, t.Key.N, t.Key.PublicKey.E, c, pt)

	select {
	case <-ch:
		t.PlainText = ln.NumberToBytes(pt)
		return nil
	case <-ctx.Done():
		return fmt.Errorf("%s failed to recover the plaintext", name)
	}
}
<|endoftext|>


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

package instrument

import (
	"time"

	"github.com/m3db/m3x/log"

	"github.com/uber-go/tally"
)

// Options represents the options for instrumentation
type Options interface {
	// SetLogger sets the logger
	SetLogger(value xlog.Logger) Options

	// Logger returns the logger
	Logger() xlog.Logger

	// SetMetricsScope sets the metricsScope
	SetMetricsScope(value tally.Scope) Options

	// MetricsScope returns the metricsScope
	MetricsScope() tally.Scope

	// SetMetricsSamplingRate sets the metrics sampling rate
	SetMetricsSamplingRate(value float64) Options

	// SetMetricsSamplingRate returns the metrics sampling rate
	MetricsSamplingRate() float64

	// ReportInterval sets time between reporting many metrics within the system
	SetReportInterval(time.Duration) Options

	// GetReportInterval returns the time between reporting many metrics within the system
	ReportInterval() time.Duration
}
<commit_msg>Add reporter interface (#48)<commit_after>// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package instrument

import (
	"time"

	"github.com/m3db/m3x/log"

	"github.com/uber-go/tally"
)

// Reporter reports information during runtime
type Reporter interface {
	// Report reports information during runtime
	Report()
}

// Options represents the options for instrumentation
type Options interface {
	// SetLogger sets the logger
	SetLogger(value xlog.Logger) Options

	// Logger returns the logger
	Logger() xlog.Logger

	// SetMetricsScope sets the metricsScope
	SetMetricsScope(value tally.Scope) Options

	// MetricsScope returns the metricsScope
	MetricsScope() tally.Scope

	// SetMetricsSamplingRate sets the metrics sampling rate
	SetMetricsSamplingRate(value float64) Options

	// SetMetricsSamplingRate returns the metrics sampling rate
	MetricsSamplingRate() float64

	// ReportInterval sets time between reporting many metrics within the system
	SetReportInterval(time.Duration) Options

	// GetReportInterval returns the time between reporting many metrics within the system
	ReportInterval() time.Duration
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"github.com/codegangsta/negroni"
	"github.com/dchest/uniuri"
	"github.com/garyburd/redigo/redis"
	"github.com/gorilla/mux"
	"github.com/mholt/binding"
	"github.com/phyber/negroni-gzip/gzip"
	"github.com/rs/cors"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"runtime"
	"time"
)

const cookieMaxAge = 60 * 60 * 60 * 24 * 30

var (
	redisPool    = redisSetup(redisConfig())
	beacon_png   = mustReadFile("assets/beacon.png")
	multi_script = redis.NewScript(-1, fmt.Sprintf("%s", mustReadFile("assets/multi.lua")))
	events       = make(chan Event, runtime.NumCPU()*100)
	version      string
)

func mustReadFile(path string) []byte {
	b, err := ioutil.ReadFile(path)
	if err != nil {
		panic(err)
	}
	return b
}

type Event struct {
	Object string
	User   string
}

type TrackJson struct {
	Visits  int64 `json:"visits"`
	Uniques int64 `json:"uniques"`
}

func (trackJson *TrackJson) FieldMap() binding.FieldMap {
	return binding.FieldMap{
		&trackJson.Visits:  "visits",
		&trackJson.Uniques: "uniques",
	}
}

func uid(w http.ResponseWriter, req *http.Request) string {
	cookie, err := req.Cookie("uid")
	if err != nil {
		switch err {
		case http.ErrNoCookie:
			uid := fmt.Sprintf("%s", uniuri.New())
			now := time.Now()
			new_cookie := &http.Cookie{Name: "uid", Value: uid, MaxAge: cookieMaxAge, Expires: now.Add(cookieMaxAge)}
			log.Print("Setting new cookie ", new_cookie)
			http.SetCookie(w, new_cookie)
			return uid
		default:
			log.Fatal(err)
			return ""
		}
	}
	return cookie.Value
}

func track() {
	conn := redisPool.Get()
	defer conn.Close()

	for {
		event := <-events
		log.Print("Tracking ", event.User, " on ", event.Object)

		// http://godoc.org/github.com/garyburd/redigo/redis#hdr-Pipelining
		conn.Send("MULTI")

		// Track the number of unique visitors in a HyperLogLog
		// http://redis.io/commands/pfadd
		conn.Send("PFADD", "hll_"+event.Object, event.User)

		// Track the total number of visits in a simple key (stringy)
		// http://redis.io/commands/incr
		conn.Send("INCR", "str_"+event.Object)

		_, err := conn.Do("EXEC")
		if err != nil {
			log.Print(err)
		}
	}
}

func beaconHandler(w http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	objectId := vars["objectId"]
	events <- Event{objectId, uid(w, req)}
	w.Header().Set("Content-Type", "image/png")
	w.Write(beacon_png)
}

func apiHandler(w http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	objectId := vars["objectId"]
	conn := redisPool.Get()
	defer conn.Close()

	uniques, err := redis.Int64(conn.Do("PFCOUNT", "hll_"+objectId))
	if err != nil {
		log.Print(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	var migrated_visits, migrated_uniques, visits int64
	mget, err := redis.Values(conn.Do("MGET", "visits_"+objectId, "uniques_"+objectId, "str_"+objectId))
	if err != nil {
		log.Print(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if _, err := redis.Scan(mget, &migrated_visits, &migrated_uniques, &visits); err != nil {
		log.Print(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	visits += migrated_visits
	uniques += migrated_uniques

	apiResponse := TrackJson{Visits: visits, Uniques: uniques}
	js, _ := json.MarshalIndent(apiResponse, "", "  ")
	w.Header().Set("Server", "Beacon "+version)
	w.Header().Set("Content-Type", "application/json")
	w.Write(js)
}

func apiMultiHandler(w http.ResponseWriter, req *http.Request) {
	conn := redisPool.Get()
	defer conn.Close()
	body, _ := ioutil.ReadAll(req.Body)
	fmt.Printf("%s\n", body)

	// TODO read from POST body
	test := []string{"foo", "bar", "baz", "blah"}

	keys := variadicScriptArgs(test)
	visits, err := redis.Int64(multi_script.Do(conn, keys...))
	if err != nil {
		log.Print(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	// TODO also query unique
	apiResponse := TrackJson{Visits: visits, Uniques: 1}
	js, _ := json.MarshalIndent(apiResponse, "", "  ")
	w.Header().Set("Content-Type", "application/json")
	w.Write(js)
}

func variadicScriptArgs(args []string) []interface{} {
	scriptArgs := make([]interface{}, len(args)+1)
	scriptArgs[0] = len(args) // First argument is length
	for i, v := range args {
		scriptArgs[i+1] = interface{}(v)
	}
	return scriptArgs
}

func apiWriteHandler(w http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	objectId := vars["objectId"]
	trackJson := new(TrackJson)
	if binding.Bind(req, trackJson).Handle(w) {
		return
	}
	fmt.Sprintf("%q\n", trackJson)
	conn := redisPool.Get()
	defer conn.Close()
	_, err := conn.Do("MSET", "uniques_"+objectId, trackJson.Uniques, "visits_"+objectId, trackJson.Visits)
	if err != nil {
		log.Print(err)
	}
}

func listenAddress() string {
	string := os.Getenv("PORT")
	if string == "" {
		return ":8080"
	} else {
		return ":" + string
	}
}

func redisConfig() (string, string) {
	redis_provider := os.Getenv("REDIS_PROVIDER")
	if redis_provider == "" {
		redis_provider = "OPENREDIS_URL"
	}
	string := os.Getenv(redis_provider)
	if string != "" {
		url, err := url.Parse(string)
		password := ""
		if err != nil {
			panic(err)
		}
		if url.User != nil {
			password, _ = url.User.Password()
		}
		return url.Host, password
	} else {
		return "127.0.0.1:6379", ""
	}
}

func redisSetup(server, password string) *redis.Pool {
	log.Print("Connecting to Redis on ", server, password)
	return &redis.Pool{
		MaxIdle:     3,
		IdleTimeout: 240 * time.Second,
		Dial: func() (redis.Conn, error) {
			c, err := redis.Dial("tcp", server)
			if err != nil {
				return nil, err
			}
			if password != "" {
				if _, err := c.Do("AUTH", password); err != nil {
					c.Close()
					return nil, err
				}
			}
			return c, err
		},
		TestOnBorrow: func(c redis.Conn, t time.Time) error {
			_, err := c.Do("PING")
			return err
		},
	}
}

func main() {
	log.Print("Beacon " + version + " running on " + fmt.Sprintf("%d", runtime.NumCPU()) + "CPUs")
	runtime.GOMAXPROCS(runtime.NumCPU())

	go track()

	r := mux.NewRouter()
	r.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
		http.Redirect(w, req, "https://www.github.com/jelder/beacon", 302)
	})
	r.HandleFunc("/{objectId}.png", beaconHandler)
	r.HandleFunc("/api/v1/{objectId}", apiHandler).Methods("GET")
	r.HandleFunc("/api/v1/_multi", apiMultiHandler).Methods("POST")
	r.HandleFunc("/api/v1/{objectId}", apiWriteHandler).Methods("POST").Queries("key", os.Getenv("SECRET_KEY"))

	r.PathPrefix("/").Handler(http.FileServer(http.Dir("./assets/")))

	n := negroni.Classic()
	n.Use(gzip.Gzip(gzip.DefaultCompression))
	n.Use(cors.New(cors.Options{
		AllowedOrigins: []string{"*"},
	}))
	n.UseHandler(r)
	n.Run(listenAddress())
}
<commit_msg>A little reorg<commit_after>package main

import (
	"fmt"
	"github.com/codegangsta/negroni"
	"github.com/dchest/uniuri"
	"github.com/garyburd/redigo/redis"
	"github.com/gorilla/mux"
	"github.com/phyber/negroni-gzip/gzip"
	"github.com/rs/cors"
	"net/http"
	"runtime"
	"time"
)

const (
	cookieMaxAge = 60 * 60 * 60 * 24 * 30
)

var (
	redisPool    *redis.Pool
	events       chan Event
	multi_script = redis.NewScript(-1, fmt.Sprintf("%s", mustReadFile("assets/multi.lua")))
	beacon_png   = mustReadFile("assets/beacon.png")
)

type Event struct {
	Object string
	User   string
}

func init() {
	redisPool = redisSetup(redisConfig())
	events = make(chan Event, runtime.NumCPU()*100)
}

func main() {
	fmt.Println("Beacon running on", fmt.Sprintf("%d", runtime.NumCPU()), "CPUs")
	runtime.GOMAXPROCS(runtime.NumCPU())

	go track()

	r := mux.NewRouter()
	r.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
		http.Redirect(w, req, "https://www.github.com/jelder/beacon", 302)
	})
	r.HandleFunc("/{objectId}.png", beaconHandler)
	r.HandleFunc("/api/v1/{objectId}", apiHandler).Methods("GET")
	r.HandleFunc("/api/v1/_multi", apiMultiHandler).Methods("POST")
	r.HandleFunc("/api/v1/{objectId}", apiWriteHandler).Methods("POST").Queries("key", ENV["SECRET_KEY"])

	r.PathPrefix("/").Handler(http.FileServer(http.Dir("./assets/")))

	n := negroni.Classic()
	n.Use(gzip.Gzip(gzip.DefaultCompression))
	n.Use(cors.New(cors.Options{
		AllowedOrigins: []string{"*"},
	}))
	n.UseHandler(r)
	n.Run(listenAddress())
}

func beaconHandler(w http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	objectId := vars["objectId"]
	events <- Event{objectId, uid(w, req)}
	w.Header().Set("Content-Type", "image/png")
	w.Write(beacon_png)
}

func uid(w http.ResponseWriter, req *http.Request) string {
	cookie, err := req.Cookie("uid")
	if err != nil {
		switch err {
		case http.ErrNoCookie:
			uid := fmt.Sprintf("%s", uniuri.New())
			now := time.Now()
			new_cookie := &http.Cookie{Name: "uid", Value: uid, MaxAge: cookieMaxAge, Expires: now.Add(cookieMaxAge)}
			fmt.Print("Setting new cookie ", new_cookie)
			http.SetCookie(w, new_cookie)
			return uid
		default:
			fmt.Println(err)
		}
	}
	return cookie.Value
}

func track() {
	conn := redisPool.Get()
	defer conn.Close()

	for {
		event := <-events
		fmt.Print("Tracking ", event.User, " on ", event.Object)

		// http://godoc.org/github.com/garyburd/redigo/redis#hdr-Pipelining
		conn.Send("MULTI")

		// Track the number of unique visitors in a HyperLogLog
		// http://redis.io/commands/pfadd
		conn.Send("PFADD", "hll_"+event.Object, event.User)

		// Track the total number of visits in a simple key (stringy)
		// http://redis.io/commands/incr
		conn.Send("INCR", "str_"+event.Object)

		_, err := conn.Do("EXEC")
		if err != nil {
			fmt.Print(err)
		}
	}
}
<|endoftext|>


<commit_before>package gokeepasslib

import (
	"bytes"
	"compress/gzip"
	"encoding/base64"
	"fmt"
	"io"
	"io/ioutil"

	w "github.com/tobischo/gokeepasslib/v3/wrappers"
)

// Binaries Stores a slice of binaries in the metadata header of a database
// This will be used only on KDBX 3.1
// Since KDBX 4, binaries are stored into the InnerHeader
type Binaries []Binary

// Binary stores a binary found in the metadata header of a database
type Binary struct {
	ID               int           `xml:"ID,attr"`         // Index of binary (Manually counted on KDBX v4)
	MemoryProtection byte          `xml:"-"`               // Memory protection flag (Only KDBX v4)
	Content          []byte        `xml:",innerxml"`       // Binary content
	Compressed       w.BoolWrapper `xml:"Compressed,attr"` // Compressed flag (Only KDBX v3.1)
}

// BinaryReference stores a reference to a binary which appears in the xml of an entry
type BinaryReference struct {
	Name  string `xml:"Key"`
	Value struct {
		ID int `xml:"Ref,attr"`
	} `xml:"Value"`
}

// Find returns a reference to a binary with the same ID as id, or nil if none if found
func (bs Binaries) Find(id int) *Binary {
	for i := range bs {
		if bs[i].ID == id {
			return &bs[i]
		}
	}
	return nil
}

// Find returns a reference to a binary in the database db with the same id as br, or nil if none is found
func (br *BinaryReference) Find(db *Database) *Binary {
	if db.Header.IsKdbx4() {
		return db.Content.InnerHeader.Binaries.Find(br.Value.ID)
	}
	return db.Content.Meta.Binaries.Find(br.Value.ID)
}

// Add appends binary data to the slice
func (bs *Binaries) Add(c []byte) *Binary {
	binary := Binary{
		Compressed: w.NewBoolWrapper(true),
	}
	if len(*bs) == 0 {
		binary.ID = 0
	} else {
		binary.ID = (*bs)[len(*bs)-1].ID + 1
	}
	binary.SetContent(c)
	*bs = append(*bs, binary)
	return &(*bs)[len(*bs)-1]
}

// GetContentBytes returns a bytes array which is the content of a binary
func (b Binary) GetContentBytes() ([]byte, error) {
	// Check for base64 content (KDBX 3.1), if it fail try with KDBX 4
	decoded := make([]byte, base64.StdEncoding.DecodedLen(len(b.Content)))
	_, err := base64.StdEncoding.Decode(decoded, b.Content)
	if err != nil {
		// KDBX 4 doesn't encode it
		decoded = b.Content[:]
	}

	if b.Compressed.Bool {
		reader, err := gzip.NewReader(bytes.NewReader(decoded))
		if err != nil {
			return nil, err
		}
		defer reader.Close()
		bts, err := ioutil.ReadAll(reader)
		if err != nil && err != io.ErrUnexpectedEOF {
			return nil, err
		}
		return bts, nil
	}
	return decoded, nil
}

// GetContentString returns a string which is the plaintext content of a binary
func (b Binary) GetContentString() (string, error) {
	data, err := b.GetContentBytes()

	if err != nil {
		return "", err
	}

	return string(data), nil
}

// GetContent returns a string which is the plaintext content of a binary
//
// Deprecated: use GetContentString() instead
func (b Binary) GetContent() (string, error) {
	return b.GetContentString()
}

// SetContent encodes and (if Compressed=true) compresses c and sets b's content
func (b *Binary) SetContent(c []byte) error {
	buff := &bytes.Buffer{}
	writer := base64.NewEncoder(base64.StdEncoding, buff)
	if b.Compressed.Bool {
		writer = gzip.NewWriter(writer)
	}
	_, err := writer.Write(c)
	if err != nil {
		return err
	}
	if err := writer.Close(); err != nil {
		return err
	}
	b.Content = buff.Bytes()
	return nil
}

// CreateReference creates a reference with the same id as b with filename f
func (b Binary) CreateReference(f string) BinaryReference {
	return NewBinaryReference(f, b.ID)
}

// NewBinaryReference creates a new BinaryReference with the given name and id
func NewBinaryReference(name string, id int) BinaryReference {
	ref := BinaryReference{}
	ref.Name = name
	ref.Value.ID = id
	return ref
}

func (b Binary) String() string {
	return fmt.Sprintf(
		"ID: %d, MemoryProtection: %x, Compressed:%#v, Content:%x",
		b.ID,
		b.MemoryProtection,
		b.Compressed,
		b.Content,
	)
}
func (br BinaryReference) String() string {
	return fmt.Sprintf("ID: %d, File Name: %s", br.Value.ID, br.Name)
}
<commit_msg>Minor comment improvement<commit_after>package gokeepasslib

import (
	"bytes"
	"compress/gzip"
	"encoding/base64"
	"fmt"
	"io"
	"io/ioutil"

	w "github.com/tobischo/gokeepasslib/v3/wrappers"
)

// Binaries Stores a slice of binaries in the metadata header of a database
// This will be used only on KDBX 3.1
// Since KDBX 4, binaries are stored into the InnerHeader
type Binaries []Binary

// Binary stores a binary found in the metadata header of a database
type Binary struct {
	ID               int           `xml:"ID,attr"`         // Index of binary (Manually counted on KDBX v4)
	MemoryProtection byte          `xml:"-"`               // Memory protection flag (Only KDBX v4)
	Content          []byte        `xml:",innerxml"`       // Binary content
	Compressed       w.BoolWrapper `xml:"Compressed,attr"` // Compressed flag (Only KDBX v3.1)
}

// BinaryReference stores a reference to a binary which appears in the xml of an entry
type BinaryReference struct {
	Name  string `xml:"Key"`
	Value struct {
		ID int `xml:"Ref,attr"`
	} `xml:"Value"`
}

// Find returns a reference to a binary with the same ID as id, or nil if none if found
func (bs Binaries) Find(id int) *Binary {
	for i := range bs {
		if bs[i].ID == id {
			return &bs[i]
		}
	}
	return nil
}

// Find returns a reference to a binary in the database db with the same id as br, or nil if none is found
func (br *BinaryReference) Find(db *Database) *Binary {
	if db.Header.IsKdbx4() {
		return db.Content.InnerHeader.Binaries.Find(br.Value.ID)
	}
	return db.Content.Meta.Binaries.Find(br.Value.ID)
}

// Add appends binary data to the slice
func (bs *Binaries) Add(c []byte) *Binary {
	binary := Binary{
		Compressed: w.NewBoolWrapper(true),
	}
	if len(*bs) == 0 {
		binary.ID = 0
	} else {
		binary.ID = (*bs)[len(*bs)-1].ID + 1
	}
	binary.SetContent(c)
	*bs = append(*bs, binary)
	return &(*bs)[len(*bs)-1]
}

// GetContentBytes returns a bytes slice containing content of a binary
func (b Binary) GetContentBytes() ([]byte, error) {
	// Check for base64 content (KDBX 3.1), if it fail try with KDBX 4
	decoded := make([]byte, base64.StdEncoding.DecodedLen(len(b.Content)))
	_, err := base64.StdEncoding.Decode(decoded, b.Content)
	if err != nil {
		// KDBX 4 doesn't encode it
		decoded = b.Content[:]
	}

	if b.Compressed.Bool {
		reader, err := gzip.NewReader(bytes.NewReader(decoded))
		if err != nil {
			return nil, err
		}
		defer reader.Close()
		bts, err := ioutil.ReadAll(reader)
		if err != nil && err != io.ErrUnexpectedEOF {
			return nil, err
		}
		return bts, nil
	}
	return decoded, nil
}

// GetContentString returns the content of a binary as a string
func (b Binary) GetContentString() (string, error) {
	data, err := b.GetContentBytes()

	if err != nil {
		return "", err
	}

	return string(data), nil
}

// GetContent returns a string which is the plaintext content of a binary
//
// Deprecated: use GetContentString() instead
func (b Binary) GetContent() (string, error) {
	return b.GetContentString()
}

// SetContent encodes and (if Compressed=true) compresses c and sets b's content
func (b *Binary) SetContent(c []byte) error {
	buff := &bytes.Buffer{}
	writer := base64.NewEncoder(base64.StdEncoding, buff)
	if b.Compressed.Bool {
		writer = gzip.NewWriter(writer)
	}
	_, err := writer.Write(c)
	if err != nil {
		return err
	}
	if err := writer.Close(); err != nil {
		return err
	}
	b.Content = buff.Bytes()
	return nil
}

// CreateReference creates a reference with the same id as b with filename f
func (b Binary) CreateReference(f string) BinaryReference {
	return NewBinaryReference(f, b.ID)
}

// NewBinaryReference creates a new BinaryReference with the given name and id
func NewBinaryReference(name string, id int) BinaryReference {
	ref := BinaryReference{}
	ref.Name = name
	ref.Value.ID = id
	return ref
}

func (b Binary) String() string {
	return fmt.Sprintf(
		"ID: %d, MemoryProtection: %x, Compressed:%#v, Content:%x",
		b.ID,
		b.MemoryProtection,
		b.Compressed,
		b.Content,
	)
}
func (br BinaryReference) String() string {
	return fmt.Sprintf("ID: %d, File Name: %s", br.Value.ID, br.Name)
}
<|endoftext|>


<commit_before>package module

import (
	"fmt"
	"github.com/davidscholberg/irkbot/lib/configure"
	"github.com/davidscholberg/irkbot/lib/message"
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/sqlite"
	"math/rand"
	"os"
	"strings"
	"time"
)

type Compliment struct {
	ID   uint   `gorm:"primary_key"`
	Text string `gorm:"unique_index:idx_compliment_text"`
}

var compliments []Compliment

func ConfigCompliment(cfg *configure.Config) {
	dbFile := cfg.Modules["compliment"]["db_file"]

	db, err := gorm.Open("sqlite3", dbFile)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return
	}
	defer db.Close()

	db.AutoMigrate(&Compliment{})

	db.Find(&compliments)

	// seed rng
	rand.Seed(time.Now().UnixNano())
}

func HelpCompliment() []string {
	s := "compliment [recipient] - give the recipient a compliment (or self if no recipient" +
		" specified)"
	return []string{s}
}

func GiveCompliment(cfg *configure.Config, in *message.InboundMsg, actions *Actions) {
	if len(compliments) == 0 {
		actions.Say("error: no compliments loaded")
		return
	}

	recipient := in.Event.Nick
	if len(in.MsgArgs) > 1 {
		recipient = strings.TrimSpace(strings.Join(in.MsgArgs[1:], " "))
	}

	response := fmt.Sprintf(
		"%s: %s",
		recipient,
		compliments[rand.Intn(len(compliments))].Text,
	)

	actions.Say(response)
}
<commit_msg>refactored compliment to load database upon each command call<commit_after>package module

import (
	"fmt"
	"github.com/davidscholberg/irkbot/lib/configure"
	"github.com/davidscholberg/irkbot/lib/message"
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/sqlite"
	"math/rand"
	"os"
	"strings"
	"time"
)

type Compliment struct {
	ID   uint   `gorm:"primary_key"`
	Text string `gorm:"unique_index:idx_compliment_text"`
}

func ConfigCompliment(cfg *configure.Config) {
	dbFile := cfg.Modules["compliment"]["db_file"]

	db, err := gorm.Open("sqlite3", dbFile)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return
	}
	defer db.Close()

	db.AutoMigrate(&Compliment{})

	// seed rng
	rand.Seed(time.Now().UnixNano())
}

func HelpCompliment() []string {
	s := "compliment [recipient] - give the recipient a compliment (or self if no recipient" +
		" specified)"
	return []string{s}
}

func GiveCompliment(cfg *configure.Config, in *message.InboundMsg, actions *Actions) {
	dbFile := cfg.Modules["compliment"]["db_file"]

	db, err := gorm.Open("sqlite3", dbFile)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		actions.Say("error: couldn't open compliment database")
		return
	}
	defer db.Close()

	compliments := []Compliment{}
	db.Find(&compliments)

	if len(compliments) == 0 {
		actions.Say("error: no compliments found")
		return
	}

	recipient := in.Event.Nick
	if len(in.MsgArgs) > 1 {
		recipient = strings.TrimSpace(strings.Join(in.MsgArgs[1:], " "))
	}

	response := fmt.Sprintf(
		"%s: %s",
		recipient,
		compliments[rand.Intn(len(compliments))].Text,
	)

	actions.Say(response)
}
<|endoftext|>