<commit_before>package plugintest

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"regexp"
	rt "runtime"
	"testing"
	"time"

	"github.com/taskcluster/slugid-go/slugid"

	"github.com/taskcluster/taskcluster-worker/engines"
	// Ensure we load the mock engine
	_ "github.com/taskcluster/taskcluster-worker/engines/mock"
	"github.com/taskcluster/taskcluster-worker/plugins"
	"github.com/taskcluster/taskcluster-worker/runtime"
	"github.com/taskcluster/taskcluster-worker/runtime/client"
	"github.com/taskcluster/taskcluster-worker/runtime/gc"
	"github.com/taskcluster/taskcluster-worker/runtime/webhookserver"
)

// The Options contains options available to any of the
// Before* or After* functions in plugintest.Case
type Options struct {
	Environment    *runtime.Environment
	SandboxBuilder engines.SandboxBuilder
	Engine         engines.Engine
	ResultSet      engines.ResultSet
	Plugin         plugins.Plugin
	TaskPlugin     plugins.TaskPlugin
}

// The Case is a testcase for a plugin. This specifies a few ways to
// ensure that the plugin has done what is expected. It
// works very closely with mockengine and using the functions
// part of the payload to modify how that works is very useful.
type Case struct {
	// A payload that will be passed to the sandbox and plugin
	Payload string
	// The plugin under test. This should be the name that is registered
	Plugin string
	// JSON configuration for the plugin
	PluginConfig string
	// Whether or not plugin.Stopped() should return true
	PluginSuccess bool
	// Whether or not engine.ResultSet.Success() should return true
	EngineSuccess bool
	// If a regular expression is specified here, it must be in the sandbox log
	MatchLog string
	// If a regular expression is specified here, it must _not_ be in the sandbox log
	NotMatchLog string
	// A mocked out queue client
	QueueMock *client.MockQueue
	// Override the default generated TaskID
	TaskID string
	// Override the default generated TaskID
	RunID int
	// A testing struct can be useful inside for assertions
	TestStruct *testing.T

	// Each of these functions is called at the time specified in the name
	BeforeBuildSandbox func(Options)
	AfterBuildSandbox  func(Options)
	BeforeStarted      func(Options)
	AfterStarted       func(Options)
	BeforeStopped      func(Options)
	AfterStopped       func(Options)
	BeforeFinished     func(Options)
	AfterFinished      func(Options)
	BeforeDisposed     func(Options)
	AfterDisposed      func(Options)
}

// Test is called to trigger a plugintest.Case to run
func (c Case) Test() {
	runtimeEnvironment := newTestEnvironment()
	engineProvider := engines.Engines()["mock"]
	engine, err := engineProvider.NewEngine(engines.EngineOptions{
		Environment: runtimeEnvironment,
		Log:         runtimeEnvironment.Log.WithField("engine", "mock"),
		// TODO: Add engine config
	})
	nilOrPanic(err)

	taskID := c.TaskID
	if taskID == "" {
		taskID = slugid.Nice()
	}

	localServer, err := webhookserver.NewLocalServer(
		net.TCPAddr{
			IP:   []byte{127, 0, 0, 1},
			Port: 60000,
		},
		"example.com",
		"",
		"",
		"",
		10*time.Minute,
	)
	nilOrPanic(err)

	context, controller, err := runtime.NewTaskContext(runtimeEnvironment.TemporaryStorage.NewFilePath(), runtime.TaskInfo{
		TaskID: taskID,
		RunID:  c.RunID,
	}, localServer)
	nilOrPanic(err)

	if c.QueueMock != nil {
		controller.SetQueueClient(c.QueueMock)
	}

	sandboxBuilder, err := engine.NewSandboxBuilder(engines.SandboxOptions{
		TaskContext: context,
		Payload:     parseEnginePayload(engine, c.Payload),
	})
	nilOrPanic(err)

	provider := plugins.Plugins()[c.Plugin]
	assert(provider != nil, "Plugin does not exist! You tried to load: ", c.Plugin)
	p, err := provider.NewPlugin(plugins.PluginOptions{
		Environment: runtimeEnvironment,
		Engine:      engine,
		Log:         runtimeEnvironment.Log.WithField("engine", "mock"),
		Config:      parsePluginConfig(provider, c.PluginConfig),
	})
	nilOrPanic(err)

	tp, err := p.NewTaskPlugin(plugins.TaskPluginOptions{
		TaskInfo: &context.TaskInfo,
		Payload:  parsePluginPayload(p, c.Payload),
	})
	nilOrPanic(err)
	// taskPlugin can be nil, if the plugin doesn't want any hooks<commit_msg>Use TestServer in plugintest<commit_after>package plugintest

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"regexp"
	rt "runtime"
	"testing"

	"github.com/taskcluster/slugid-go/slugid"

	"github.com/taskcluster/taskcluster-worker/engines"
	// Ensure we load the mock engine
	_ "github.com/taskcluster/taskcluster-worker/engines/mock"
	"github.com/taskcluster/taskcluster-worker/plugins"
	"github.com/taskcluster/taskcluster-worker/runtime"
	"github.com/taskcluster/taskcluster-worker/runtime/client"
	"github.com/taskcluster/taskcluster-worker/runtime/gc"
	"github.com/taskcluster/taskcluster-worker/runtime/webhookserver"
)

// The Options contains options available to any of the
// Before* or After* functions in plugintest.Case
type Options struct {
	Environment    *runtime.Environment
	SandboxBuilder engines.SandboxBuilder
	Engine         engines.Engine
	ResultSet      engines.ResultSet
	Plugin         plugins.Plugin
	TaskPlugin     plugins.TaskPlugin
}

// The Case is a testcase for a plugin. This specifies a few ways to
// ensure that the plugin has done what is expected. It
// works very closely with mockengine and using the functions
// part of the payload to modify how that works is very useful.
type Case struct {
	// A payload that will be passed to the sandbox and plugin
	Payload string
	// The plugin under test. This should be the name that is registered
	Plugin string
	// JSON configuration for the plugin
	PluginConfig string
	// Whether or not plugin.Stopped() should return true
	PluginSuccess bool
	// Whether or not engine.ResultSet.Success() should return true
	EngineSuccess bool
	// If a regular expression is specified here, it must be in the sandbox log
	MatchLog string
	// If a regular expression is specified here, it must _not_ be in the sandbox log
	NotMatchLog string
	// A mocked out queue client
	QueueMock *client.MockQueue
	// Override the default generated TaskID
	TaskID string
	// Override the default generated TaskID
	RunID int
	// A testing struct can be useful inside for assertions
	TestStruct *testing.T

	// Each of these functions is called at the time specified in the name
	BeforeBuildSandbox func(Options)
	AfterBuildSandbox  func(Options)
	BeforeStarted      func(Options)
	AfterStarted       func(Options)
	BeforeStopped      func(Options)
	AfterStopped       func(Options)
	BeforeFinished     func(Options)
	AfterFinished      func(Options)
	BeforeDisposed     func(Options)
	AfterDisposed      func(Options)
}

// Test is called to trigger a plugintest.Case to run
func (c Case) Test() {
	runtimeEnvironment := newTestEnvironment()

	testServer, err := webhookserver.NewTestServer()
	nilOrPanic(err)
	defer testServer.Stop()
	runtimeEnvironment.WebHookServer = testServer

	engineProvider := engines.Engines()["mock"]
	engine, err := engineProvider.NewEngine(engines.EngineOptions{
		Environment: runtimeEnvironment,
		Log:         runtimeEnvironment.Log.WithField("engine", "mock"),
		// TODO: Add engine config
	})
	nilOrPanic(err)

	taskID := c.TaskID
	if taskID == "" {
		taskID = slugid.Nice()
	}

	context, controller, err := runtime.NewTaskContext(runtimeEnvironment.TemporaryStorage.NewFilePath(), runtime.TaskInfo{
		TaskID: taskID,
		RunID:  c.RunID,
	}, testServer)
	nilOrPanic(err)

	if c.QueueMock != nil {
		controller.SetQueueClient(c.QueueMock)
	}

	sandboxBuilder, err := engine.NewSandboxBuilder(engines.SandboxOptions{
		TaskContext: context,
		Payload:     parseEnginePayload(engine, c.Payload),
	})
	nilOrPanic(err)

	provider := plugins.Plugins()[c.Plugin]
	assert(provider != nil, "Plugin does not exist! You tried to load: ", c.Plugin)
	p, err := provider.NewPlugin(plugins.PluginOptions{
		Environment: runtimeEnvironment,
		Engine:      engine,
		Log:         runtimeEnvironment.Log.WithField("engine", "mock"),
		Config:      parsePluginConfig(provider, c.PluginConfig),
	})
	nilOrPanic(err)

	tp, err := p.NewTaskPlugin(plugins.TaskPluginOptions{
		TaskInfo: &context.TaskInfo,
		Payload:  parsePluginPayload(p, c.Payload),
	})
	nilOrPanic(err)
	// taskPlugin can be nil, if the plugin doesn't want any hooks
{'fraction_non_alphanumeric': 0.09334945586457073, 'fraction_numerical': 0.0015719467956469165, 'mean_word_length': 4.089846153846154, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4532018', 'n_tokens_mistral': 2582, 'n_tokens_neox': 2495, 'n_words': 746}