github.com/braveheart12/insolar-09-08-19@v0.8.7/functest/main_test.go (about)

     1  // +build functest
     2  
     3  /*
     4   *    Copyright 2019 Insolar Technologies
     5   *
     6   *    Licensed under the Apache License, Version 2.0 (the "License");
     7   *    you may not use this file except in compliance with the License.
     8   *    You may obtain a copy of the License at
     9   *
    10   *        http://www.apache.org/licenses/LICENSE-2.0
    11   *
    12   *    Unless required by applicable law or agreed to in writing, software
    13   *    distributed under the License is distributed on an "AS IS" BASIS,
    14   *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    15   *    See the License for the specific language governing permissions and
    16   *    limitations under the License.
    17   */
    18  
    19  package functest
    20  
    21  import (
    22  	"bufio"
    23  	"encoding/json"
    24  	"fmt"
    25  	"go/build"
    26  	"io"
    27  	"io/ioutil"
    28  	"os"
    29  	"os/exec"
    30  	"path/filepath"
    31  	"strings"
    32  	"syscall"
    33  	"testing"
    34  	"time"
    35  
    36  	yaml "gopkg.in/yaml.v2"
    37  
    38  	"github.com/insolar/insolar/api/requester"
    39  	"github.com/insolar/insolar/core"
    40  	"github.com/insolar/insolar/logicrunner/goplugin/goplugintestutils"
    41  	"github.com/pkg/errors"
    42  )
    43  
    44  const HOST = "http://localhost:19101"
    45  const TestAPIURL = HOST + "/api"
    46  const TestRPCUrl = TestAPIURL + "/rpc"
    47  const TestCallUrl = TestAPIURL + "/call"
    48  
    49  const insolarRootMemberKeys = "root_member_keys.json"
    50  
    51  const conf_dir = "../scripts/insolard/"
    52  
    53  var cmd *exec.Cmd
    54  var cmdCompleted = make(chan error, 1)
    55  var stdin io.WriteCloser
    56  var stdout io.ReadCloser
    57  var stderr io.ReadCloser
    58  
    59  var insolarRootMemberKeysPath = filepath.Join(conf_dir+"/configs", insolarRootMemberKeys)
    60  
    61  var info *requester.InfoResponse
    62  var root user
    63  
    64  type user struct {
    65  	ref     string
    66  	privKey string
    67  	pubKey  string
    68  }
    69  
    70  func getNumberNodes() (int, error) {
    71  	type genesisConf struct {
    72  		DiscoverNodes []interface{} `yaml:"discovery_nodes"`
    73  	}
    74  
    75  	var conf genesisConf
    76  
    77  	buff, err := ioutil.ReadFile(conf_dir + "/genesis.yaml")
    78  	if err != nil {
    79  		return 0, errors.Wrap(err, "[ getNumberNodes ] Can't read genesis conf")
    80  	}
    81  
    82  	err = yaml.Unmarshal(buff, &conf)
    83  	if err != nil {
    84  		return 0, errors.Wrap(err, "[ getNumberNodes ] Can't parse genesis conf")
    85  	}
    86  
    87  	return len(conf.DiscoverNodes), nil
    88  }
    89  
    90  func functestPath() string {
    91  	p, err := build.Default.Import("github.com/insolar/insolar", "", build.FindOnly)
    92  	if err != nil {
    93  		panic(err)
    94  	}
    95  	return filepath.Join(p.Dir, "functest")
    96  }
    97  
    98  func createDirForContracts() error {
    99  	return os.MkdirAll(filepath.Join(functestPath(), "contractstorage"), 0777)
   100  }
   101  
   102  func deleteDirForContracts() error {
   103  	return os.RemoveAll(filepath.Join(functestPath(), "contractstorage"))
   104  }
   105  
   106  func loadRootKeys() error {
   107  	text, err := ioutil.ReadFile(insolarRootMemberKeysPath)
   108  	if err != nil {
   109  		return errors.Wrapf(err, "[ loadRootKeys ] could't load root keys")
   110  	}
   111  	var data map[string]string
   112  	err = json.Unmarshal(text, &data)
   113  	if err != nil {
   114  		return errors.Wrapf(err, "[ loadRootKeys ] could't unmarshal root keys")
   115  	}
   116  	if data["private_key"] == "" || data["public_key"] == "" {
   117  		return errors.New("[ loadRootKeys ] could't find any keys")
   118  	}
   119  	root.privKey = data["private_key"]
   120  	root.pubKey = data["public_key"]
   121  
   122  	return nil
   123  }
   124  
   125  func setInfo() error {
   126  	var err error
   127  	info, err = requester.Info(TestAPIURL)
   128  	if err != nil {
   129  		return errors.Wrap(err, "[ setInfo ] error sending request")
   130  	}
   131  	return nil
   132  }
   133  
   134  var insgorundPath string
   135  
   136  func buildGinsiderCLI() (err error) {
   137  	insgorundPath, _, err = goplugintestutils.Build()
   138  	return errors.Wrap(err, "[ buildGinsiderCLI ] could't build ginsider CLI: ")
   139  }
   140  
   141  func stopInsolard() error {
   142  	if stdin != nil {
   143  		defer stdin.Close()
   144  	}
   145  	if stdout != nil {
   146  		defer stdout.Close()
   147  	}
   148  
   149  	if cmd == nil || cmd.Process == nil {
   150  		return nil
   151  	}
   152  
   153  	err := cmd.Process.Signal(syscall.SIGHUP)
   154  	if err != nil {
   155  		return errors.Wrap(err, "[ stopInsolard ] failed to kill process:")
   156  	}
   157  
   158  	pState, err := cmd.Process.Wait()
   159  	if err != nil {
   160  		return errors.Wrap(err, "[ stopInsolard ] failed to wait process:")
   161  	}
   162  
   163  	fmt.Println("[ stopInsolard ] State: ", pState.String())
   164  
   165  	return nil
   166  }
   167  
   168  var insgorundCleaner func()
   169  var secondInsgorundCleaner func()
   170  
   171  func startInsgorund(listenPort string, upstreamPort string) (func(), error) {
   172  	// It starts on ports of "virtual" node
   173  	cleaner, err := goplugintestutils.StartInsgorund(insgorundPath, "tcp", "127.0.0.1:"+listenPort, "tcp", "127.0.0.1:"+upstreamPort)
   174  	if err != nil {
   175  		return cleaner, errors.Wrap(err, "[ startInsgorund ] couldn't wait for insolard to start completely: ")
   176  	}
   177  	return cleaner, nil
   178  }
   179  
   180  func startAllInsgorunds() (err error) {
   181  	insgorundCleaner, err = startInsgorund("33305", "33306")
   182  	if err != nil {
   183  		return errors.Wrap(err, "[ setup ] could't start insgorund: ")
   184  	}
   185  	fmt.Println("[ startAllInsgorunds ] insgorund was successfully started")
   186  
   187  	secondInsgorundCleaner, err = startInsgorund("33327", "33328")
   188  	if err != nil {
   189  		return errors.Wrap(err, "[ setup ] could't start second insgorund: ")
   190  	}
   191  	fmt.Println("[ startAllInsgorunds ] second insgorund was successfully started")
   192  
   193  	return nil
   194  }
   195  
   196  func stopAllInsgorunds() error {
   197  	if insgorundCleaner == nil || secondInsgorundCleaner == nil {
   198  		return errors.New("[ stopInsgorund ] cleaner func not found")
   199  	}
   200  	insgorundCleaner()
   201  	secondInsgorundCleaner()
   202  	return nil
   203  }
   204  
   205  func waitForNet() error {
   206  	numAttempts := 90
   207  	ports := []string{"19101", "19102", "19103", "19104", "19105"}
   208  	numNodes := len(ports)
   209  	currentOk := 0
   210  	for i := 0; i < numAttempts; i++ {
   211  		currentOk = 0
   212  		for _, port := range ports {
   213  			resp, err := requester.Status(fmt.Sprintf("http://127.0.0.1:%s/api", port))
   214  			if err != nil {
   215  				fmt.Println("[ waitForNet ] Problem with port " + port + ". Err: " + err.Error())
   216  				break
   217  			}
   218  			if resp.NetworkState != core.CompleteNetworkState.String() {
   219  				fmt.Println("[ waitForNet ] Good response from port " + port + ". Net is not ready. Response: " + resp.NetworkState)
   220  				break
   221  			}
   222  			fmt.Println("[ waitForNet ] Good response from port " + port + ". Net is ready. Response: " + resp.NetworkState)
   223  			currentOk++
   224  		}
   225  		if currentOk == numNodes {
   226  			fmt.Printf("[ waitForNet ] All %d nodes have started\n", numNodes)
   227  			break
   228  		}
   229  
   230  		time.Sleep(time.Second)
   231  		fmt.Printf("[ waitForNet ] Waiting for net: attempt %d/%d\n", i, numAttempts)
   232  	}
   233  
   234  	if currentOk != numNodes {
   235  		return errors.New("[ waitForNet ] Can't Start net: No attempts left")
   236  	}
   237  
   238  	return nil
   239  }
   240  
   241  func startNet() error {
   242  	cwd, err := os.Getwd()
   243  	if err != nil {
   244  		return errors.Wrap(err, "[ startNet ] Can't get current working directory")
   245  	}
   246  	defer os.Chdir(cwd)
   247  
   248  	err = os.Chdir("../")
   249  	if err != nil {
   250  		return errors.Wrap(err, "[ startNet  ] Can't change dir")
   251  	}
   252  
   253  	cmd = exec.Command("./scripts/insolard/launchnet.sh", "-ngw")
   254  	stdout, _ = cmd.StdoutPipe()
   255  	if err != nil {
   256  		return errors.Wrap(err, "[ startNet ] could't set stdout: ")
   257  	}
   258  
   259  	stderr, err = cmd.StderrPipe()
   260  	if err != nil {
   261  		return errors.Wrap(err, "[ startNet] could't set stderr: ")
   262  	}
   263  
   264  	err = cmd.Start()
   265  	if err != nil {
   266  		return errors.Wrap(err, "[ startNet ] Can't run cmd")
   267  	}
   268  
   269  	err = waitForLaunch()
   270  	if err != nil {
   271  		return errors.Wrap(err, "[ startNet ] couldn't waitForLaunch more")
   272  	}
   273  
   274  	err = waitForNet()
   275  	if err != nil {
   276  		return errors.Wrap(err, "[ startNet ] couldn't waitForNet more")
   277  	}
   278  
   279  	return nil
   280  
   281  }
   282  
   283  func waitForLaunch() error {
   284  	done := make(chan bool, 1)
   285  	timeout := 240 * time.Second
   286  
   287  	go func() {
   288  		scanner := bufio.NewScanner(stdout)
   289  		fmt.Println("Insolard output: ")
   290  		for scanner.Scan() {
   291  			line := scanner.Text()
   292  			fmt.Println(line)
   293  			if strings.Contains(line, "start discovery nodes ...") {
   294  				done <- true
   295  			}
   296  		}
   297  	}()
   298  	go func() {
   299  		scanner := bufio.NewScanner(stderr)
   300  		for scanner.Scan() {
   301  			line := scanner.Text()
   302  			fmt.Println(line)
   303  		}
   304  	}()
   305  
   306  	go func() { cmdCompleted <- cmd.Wait() }()
   307  	select {
   308  	case err := <-cmdCompleted:
   309  		cmdCompleted <- nil
   310  		return errors.New("[ waitForLaunch ] insolard finished unexpectedly: " + err.Error())
   311  	case <-done:
   312  		return nil
   313  	case <-time.After(timeout):
   314  		return errors.Errorf("[ waitForLaunch ] could't wait for launch: timeout of %s was exceeded", timeout)
   315  	}
   316  }
   317  
   318  func setup() error {
   319  	err := createDirForContracts()
   320  	if err != nil {
   321  		return errors.Wrap(err, "[ setup ] could't create dirs for test: ")
   322  	}
   323  	fmt.Println("[ setup ] directory for contracts cache was successfully created")
   324  
   325  	err = buildGinsiderCLI()
   326  	if err != nil {
   327  		return errors.Wrap(err, "[ setup ] could't build ginsider CLI: ")
   328  	}
   329  	fmt.Println("[ setup ] ginsider CLI was successfully builded")
   330  
   331  	err = startAllInsgorunds()
   332  	if err != nil {
   333  		return errors.Wrap(err, "[ setup ] could't start insgorund: ")
   334  	}
   335  	fmt.Println("[ setup ] insgorund was successfully started")
   336  
   337  	err = startNet()
   338  	if err != nil {
   339  		return errors.Wrap(err, "[ setup ] could't startNet")
   340  	}
   341  
   342  	err = loadRootKeys()
   343  	if err != nil {
   344  		return errors.Wrap(err, "[ setup ] could't load root keys: ")
   345  	}
   346  	fmt.Println("[ setup ] root keys successfully loaded")
   347  
   348  	numAttempts := 60
   349  	for i := 0; i < numAttempts; i++ {
   350  		err = setInfo()
   351  		if err != nil {
   352  			fmt.Printf("[ setup ] Couldn't setInfo. Attempt %d/%d. Err: %s\n", i, numAttempts, err)
   353  		} else {
   354  			break
   355  		}
   356  		time.Sleep(time.Second)
   357  	}
   358  	if err != nil {
   359  		return errors.Wrap(err, "[ setup ] could't receive root reference ")
   360  	}
   361  
   362  	fmt.Println("[ setup ] root reference successfully received")
   363  	root.ref = info.RootMember
   364  
   365  	return nil
   366  }
   367  
   368  func teardown() {
   369  	var envSetting = os.Getenv("TEST_ENV")
   370  	var err error
   371  	fmt.Println("TEST_ENV: ", envSetting)
   372  	if envSetting != "CI" {
   373  		err = stopInsolard()
   374  
   375  		if err != nil {
   376  			fmt.Println("[ teardown ]  failed to stop insolard: ", err)
   377  		}
   378  		fmt.Println("[ teardown ] insolard was successfully stoped")
   379  	}
   380  
   381  	err = stopAllInsgorunds()
   382  	if err != nil {
   383  		fmt.Println("[ teardown ]  failed to stop all insgrounds: ", err)
   384  	}
   385  	fmt.Println("[ teardown ] insgorund was successfully stoped")
   386  
   387  	err = deleteDirForContracts()
   388  	if err != nil {
   389  		fmt.Println("[ teardown ] failed to remove directory for contracts cache for func tests: ", err)
   390  	}
   391  	fmt.Println("[ teardown ] directory for contracts cache was successfully deleted")
   392  }
   393  
   394  func testMainWrapper(m *testing.M) int {
   395  	err := setup()
   396  	defer teardown()
   397  	if err != nil {
   398  		fmt.Println("error while setup, skip tests: ", err)
   399  		return 1
   400  	}
   401  	code := m.Run()
   402  	return code
   403  }
   404  
   405  func TestMain(m *testing.M) {
   406  	os.Exit(testMainWrapper(m))
   407  }