diff --git a/.gitignore b/.gitignore index 1e17d64d0..e026b3fbf 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,4 @@ examples.txt node_modules nohup.out .raw +*.zip diff --git a/components/testing/.dockerignore b/components/testing/.dockerignore index 698c05384..184d4d10c 100644 --- a/components/testing/.dockerignore +++ b/components/testing/.dockerignore @@ -1,5 +1,6 @@ .tool-versions Dockerfile +infrastructure **/node_modules **/nohup.out **/.prettierrc diff --git a/components/testing/infrastructure/.terraform.lock.hcl b/components/testing/infrastructure/.terraform.lock.hcl new file mode 100644 index 000000000..d3b2ec0a7 --- /dev/null +++ b/components/testing/infrastructure/.terraform.lock.hcl @@ -0,0 +1,62 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/archive" { + version = "2.4.2" + hashes = [ + "h1:1eOz9vM/55vnQjxk23RhnYga7PZq8n2rGxG+2Vx2s6w=", + "zh:08faed7c9f42d82bc3d406d0d9d4971e2d1c2d34eae268ad211b8aca57b7f758", + "zh:3564112ed2d097d7e0672378044a69b06642c326f6f1584d81c7cdd32ebf3a08", + "zh:53cd9afd223c15828c1916e68cb728d2be1cbccb9545568d6c2b122d0bac5102", + "zh:5ae4e41e3a1ce9d40b6458218a85bbde44f21723943982bca4a3b8bb7c103670", + "zh:5b65499218b315b96e95c5d3463ea6d7c66245b59461217c99eaa1611891cd2c", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:7f45b35a8330bebd184c2545a41782ff58240ed6ba947274d9881dd5da44b02e", + "zh:87e67891033214e55cfead1391d68e6a3bf37993b7607753237e82aa3250bb71", + "zh:de3590d14037ad81fc5cedf7cfa44614a92452d7b39676289b704a962050bc5e", + "zh:e7e6f2ea567f2dbb3baa81c6203be69f9cd6aeeb01204fd93e3cf181e099b610", + "zh:fd24d03c89a7702628c2e5a3c732c0dede56fa75a08da4a1efe17b5f881c88e2", + "zh:febf4b7b5f3ff2adff0573ef6361f09b6638105111644bdebc0e4f575373935f", + ] +} + +provider "registry.terraform.io/hashicorp/aws" { + version = "5.58.0" + hashes = [ + "h1:XnAwb/MGeP7sxz/0SKLQF1ujaP7Bg15ol+ca7KZruio=", + "zh:15e9be54a8febe8e560362b10967cb60b680ca3f78fe207d7209b76e076f59d3", + "zh:240f6899a2cec259aa2729ce031f6af2b453f90a8b59118bb2571c54acc65db8", + "zh:2b6e8e2ab1a3dce1001503dba6086a128bb2a71652b0d0b3b107db665b7d6881", + "zh:579b0ed95247a0bd8bfb3fac7fb767547dde76026c578f4f184b5743af5e32cc", + "zh:6adcd10fd12be0be9eb78a89e745a5b77ae0d8b3522cd782456a71178aad8ccb", + "zh:7f829cef82f0a02faa97d0fbe1417a40b73fc5142e883b12eebc5b71015efac9", + "zh:81977f001998c9096f7b59710996e159774a9313c1bc03db3beb81c3e016ebef", + "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", + "zh:a5d98ac6fab6e6c85164ca7dd38f94a1e44bd70c0e8354c61f7fbabf698957cd", + "zh:c27fa4fed50f6f83ca911bef04f05d635a7b7a01a89dc8fc5d66a277588f08df", + "zh:d4042bdf86ca6dc10e0cca91c4fcc592b12572d26185b3d37bbbb9e2026ac68b", + "zh:d536482cf4ace0d49a2a86c931150921649beae59337d0c02a785879fe943cf3", + "zh:e205f8243274a621fb9ef2b5e2c71e84c1670be1d23697739439f5a831fa620f", + "zh:eb76ce0c77fd76c47f57122c91c4fcf0f72c01423538ed7833eaa7eeaae2edf6", + "zh:ffe04e494af6cc7348ceb8d85f4c1d5a847a44510827b4496513c810a4d9196d", + ] +} + +provider "registry.terraform.io/hashicorp/cloudinit" { + version = "2.3.4" + hashes = [ + "h1:S3j8poSaLbaftlKq2STBkQEkZH253ZLaHhBHBifdpBQ=", + "zh:09f1f1e1d232da96fbf9513b0fb5263bc2fe9bee85697aa15d40bb93835efbeb", + "zh:381e74b90d7a038c3a8dcdcc2ce8c72d6b86da9f208a27f4b98cabe1a1032773", + "zh:398eb321949e28c4c5f7c52e9b1f922a10d0b2b073b7db04cb69318d24ffc5a9", + "zh:4a425679614a8f0fe440845828794e609b35af17db59134c4f9e56d61e979813", + "zh:4d955d8608ece4984c9f1dacda2a59fdb4ea6b0243872f049b388181aab8c80a", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:a48fbee1d58d55a1f4c92c2f38c83a37c8b2f2701ed1a3c926cefb0801fa446a", + "zh:b748fe6631b16a1dafd35a09377c3bffa89552af584cf95f47568b6cd31fc241", + "zh:d4b931f7a54603fa4692a2ec6e498b95464babd2be072bed5c7c2e140a280d99", + "zh:f1c9337fcfe3a7be39d179eb7986c22a979cfb2c587c05f1b3b83064f41785c5", + "zh:f58fc57edd1ee3250a28943cd84de3e4b744cdb52df0356a53403fc240240636", + "zh:f5f50de0923ff530b03e1bca0ac697534d61bb3e5fc7f60e13becb62229097a9", + ] +} diff --git a/components/testing/infrastructure/Dockerfile b/components/testing/infrastructure/Dockerfile new file mode 100644 index 000000000..6564aeb65 --- /dev/null +++ b/components/testing/infrastructure/Dockerfile @@ -0,0 +1,7 @@ +FROM public.ecr.aws/docker/library/alpine:latest + +RUN apk update && apk upgrade && apk add --update --no-cache jq sipp curl + +COPY --link tests tests + +WORKDIR /tests diff --git a/components/testing/infrastructure/README.md b/components/testing/infrastructure/README.md new file mode 100644 index 000000000..b912cb1d4 --- /dev/null +++ b/components/testing/infrastructure/README.md @@ -0,0 +1,14 @@ +# Somleng E2E Integration Tests + +This directory contains infrastructure and end-to-end tests for testing Somleng. + +## Setup + +1. Run `terraform apply` +2. Open a SSM session to `somleng-switch-testing` +3. Run `sudo docker ps` +4. Run `sudo docker exec -it /bin/sh` + +## Cleanup + +1. Run `terraform destroy` diff --git a/components/testing/infrastructure/ec2.tf b/components/testing/infrastructure/ec2.tf new file mode 100644 index 000000000..c988f844a --- /dev/null +++ b/components/testing/infrastructure/ec2.tf @@ -0,0 +1,96 @@ +data "aws_ssm_parameter" "arm64_ami" { + name = "/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-arm64" +} + +data "archive_file" "test_files" { + type = "zip" + source_dir = "${path.module}/tests" + output_path = "${path.module}/tests_files.zip" +} + +resource "aws_security_group" "this" { + name = "somleng-switch-testing" + vpc_id = data.terraform_remote_state.core_infrastructure.outputs.vpc.vpc_id +} + +resource "aws_security_group_rule" "egress" { + type = "egress" + to_port = 0 + protocol = "-1" + from_port = 0 + security_group_id = aws_security_group.this.id + cidr_blocks = ["0.0.0.0/0"] +} + +resource "aws_instance" "this" { + ami = data.aws_ssm_parameter.arm64_ami.value + instance_type = "t4g.small" + security_groups = [ + aws_security_group.this.id, + ] + subnet_id = element(data.terraform_remote_state.core_infrastructure.outputs.vpc.public_subnets, 0) + associate_public_ip_address = true + iam_instance_profile = aws_iam_instance_profile.this.id + + root_block_device { + volume_size = 100 + volume_type = "gp3" + } + + tags = { + Name = "somleng-switch-testing" + } + + user_data = base64encode(join("\n", [ + "#cloud-config", + yamlencode({ + # https://cloudinit.readthedocs.io/en/latest/topics/modules.html + write_files : [ + { + path : "/opt/testing/setup.sh", + content : file("${path.module}/setup.sh"), + permissions : "0755", + }, + { + path : "/opt/testing/Dockerfile", + content : file("${path.module}/Dockerfile"), + }, + { + encoding : "b64", + path : "/opt/testing/test_files.zip", + content : filebase64(data.archive_file.test_files.output_path), + }, + ], + runcmd : [ + ["/opt/testing/setup.sh"] + ], + }) + ])) +} + +resource "aws_iam_role" "this" { + name = "somleng-switch-testing" + + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "ec2.amazonaws.com" + } + } + ] + }) +} + +resource "aws_iam_instance_profile" "this" { + name = aws_iam_role.this.name + role = aws_iam_role.this.name +} + +resource "aws_iam_role_policy_attachment" "ssm" { + role = aws_iam_role.this.name + policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM" +} diff --git a/components/testing/infrastructure/setup.sh b/components/testing/infrastructure/setup.sh new file mode 100644 index 000000000..8512fa88d --- /dev/null +++ b/components/testing/infrastructure/setup.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +# Get this data from inside EC2 instance +# TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"` +# curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/user-data + +set -e + +dnf update +dnf install -y docker +service docker start + +unzip /opt/testing/test_files.zip -d /opt/testing/tests +docker build -t "testing:latest" /opt/testing +docker run --rm -d testing:latest tail -f /dev/null diff --git a/components/testing/infrastructure/terraform.tf b/components/testing/infrastructure/terraform.tf new file mode 100644 index 000000000..d8a25b2bf --- /dev/null +++ b/components/testing/infrastructure/terraform.tf @@ -0,0 +1,22 @@ +terraform { + backend "s3" { + bucket = "infrastructure.somleng.org" + key = "somleng_switch_testing.tfstate" + encrypt = true + region = "ap-southeast-1" + } +} + +provider "aws" { + region = var.aws_region +} + +data "terraform_remote_state" "core_infrastructure" { + backend = "s3" + + config = { + bucket = "infrastructure.somleng.org" + key = "core.tfstate" + region = var.aws_region + } +} diff --git a/components/testing/infrastructure/tests/public_gateway_alternative_inbound_test.sh b/components/testing/infrastructure/tests/public_gateway_alternative_inbound_test.sh new file mode 100755 index 000000000..d0ae97251 --- /dev/null +++ b/components/testing/infrastructure/tests/public_gateway_alternative_inbound_test.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +set -e + +TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"` +AWS_PUBLIC_IP=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/public-ipv4) +DESTINATION_NUMBER="1234" +HOSTNAME=$(cat /etc/hostname) + +read -p "1. Add (or modify) a SIP trunk on Somleng with the following Source IP for Inbound Dialing: $AWS_PUBLIC_IP. Press any key when done." +read -p "2. Configure the number: $DESTINATION_NUMBER on Somleng: Press any key when done." +read -p "3. Start TCP dump. In another terminal run the following: sudo docker run -it --rm --net container:$HOSTNAME nicolaka/netshoot followed by tcpdump -Xvv -i eth0 -s0 -w capture.pcap. Press any key when done." + +log_file="uac_*_messages.log" +rm -f $log_file + +sipp -sf scenarios/uac.xml 15.197.218.231:5080 -key username "+855715100850" -s 1234 -m 1 -trace_msg > /dev/null diff --git a/components/testing/infrastructure/tests/scenarios/uac.xml b/components/testing/infrastructure/tests/scenarios/uac.xml new file mode 100644 index 000000000..81f3ca9dc --- /dev/null +++ b/components/testing/infrastructure/tests/scenarios/uac.xml @@ -0,0 +1,119 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + ;tag=[pid]SIPpTag00[call_number] + To: [service] + Call-ID: [call_id] + CSeq: 1 INVITE + Contact: sip:[username]@[local_ip]:[local_port] + Max-Forwards: 70 + Subject: Performance Test + Content-Type: application/sdp + Content-Length: [len] + + v=0 + o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip] + s=- + c=IN IP[media_ip_type] [media_ip] + t=0 0 + m=audio [media_port] RTP/AVP 0 + a=rtpmap:0 PCMU/8000 + + ]]> + + + + + + + + + + + + + + + + + + + + + ;tag=[pid]SIPpTag00[call_number] + To: [service] [peer_tag_param] + Call-ID: [call_id] + CSeq: 1 ACK + Contact: sip:[username]@[local_ip]:[local_port] + Max-Forwards: 70 + Subject: Performance Test + Content-Length: 0 + [routes] + + ]]> + + + + + + + + + ;tag=[pid]SIPpTag00[call_number] + To: [service] [peer_tag_param] + Call-ID: [call_id] + CSeq: 2 BYE + Contact: sip:[username]@[local_ip]:[local_port] + Max-Forwards: 70 + Subject: Performance Test + Content-Length: 0 + [routes] + + ]]> + + + + + + + + + + + + diff --git a/components/testing/infrastructure/variables.tf b/components/testing/infrastructure/variables.tf new file mode 100644 index 000000000..aaa8897e9 --- /dev/null +++ b/components/testing/infrastructure/variables.tf @@ -0,0 +1,3 @@ +variable "aws_region" { + default = "ap-southeast-1" +} diff --git a/components/testing/infrastructure/versions.tf b/components/testing/infrastructure/versions.tf new file mode 100644 index 000000000..1d23dfe5c --- /dev/null +++ b/components/testing/infrastructure/versions.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + } + } + required_version = ">= 0.13" +}