preface
First, a few important concepts emerge from this article:
Function Compute: Function Compute is an event-driven service that lets the user write code and upload it instead of managing the server. Function computing prepares computing resources and runs user code on an elastic scale, with users paying only for the resources consumed by the actual code running. Function calculation refer to more information. Funcraft: Funcraft is a tool used to support Serverless application deployment. Funcraft helps you easily manage functions, API gateways, logging services, and other resources. It helps you develop, build, and deploy through a resource configuration file (template.yml). More documentation references for Fun. OSS: object storage. Massive, secure, low-cost and highly reliable cloud storage services provide 99.9999999999% data reliability. RESTful apis are used to store and access data in any location on the Internet. Capacity and processing capabilities are flexibly expanded, and storage costs are optimized for multiple storage types. ROS: Resource Choreography (ROS) is an easy-to-use cloud computing resource management and automated operation and maintenance service. Users can use templates to describe the dependencies and configurations of multiple cloud computing resources, and automatically create and configure all resources for automatic deployment, operation and maintenance (O&M). Choreography templates are also a standardized way of delivering resources and applications that can be edited at any time, enabling Infrastructure as Code. CI/CD: CI/CD is a method of frequently delivering applications to customers by introducing automation in the application development phase. The core concepts of CI/CD are continuous integration, continuous delivery, and continuous deployment.
The target
This article intends to use a simple functional calculation project as an example to write test cases and configure them to support CI/CD workflows. Achieve the following four mini-goals:
- The CI is triggered by a Git commit
- Perform tests (unit, integration, and end-to-end)
- Functions are packaged and uploaded to OSS
- ROS deployment functions to the Staging environment
Work flow chart
The familiar Github repository is used here, in conjunction with Travis CI. When a user pushes or PR (Pull Request) on the sample project, the Travis CI is automatically triggered for unit testing, build packaging, and deployment publishing.
The sample project
The example project address is: github.com/vangie/tz-t… , the project is a simple Web function based on FC Http trigger, which returns the current time in a specified time zone. The project directory structure is as follows
Tz - time ├ ─ ─. Funignore ├ ─ ─. Travis. Yml ├ ─ ─ a Makefile ├ ─ ─ bin │ ├ ─ ─ delRosStack. Sh │ ├ ─ ─ deployE2EStack. Sh │ └ ─ ─wait├─ Index. Integration.js ├─ Index.js ├─ Index.js ├─ index.js ├─ Jest. Config. E2e. Js ├ ─ ─ jest. Config. Integration. Js ├ ─ ─ package - lock. Json ├ ─ ─ package. The json └ ─ ─ the template. The ymlCopy the code
Functions of some documents:
.funignore
– Funcraft Sudden file list during deployment.travis.yml
– Travis CI configuration fileindex.js
– Function entry file- *.test.js – Unit test related files
- *.integraion-test.js – Integration test related files
- *.e23-test.js – End-to-end test related files
- Template.yml-ros description file used to describe functions and other cloud services
Automated testing
Tests usually fall into three categories: unit tests, integration tests, and E2E tests. In a functional computing scenario, these three types of tests can be implemented as follows.
- Unit testing – Use Mock classes to test functions and validate input and output parameters
- Integration testing – use
fun local invoke/start
Analog running function - E2E testing – Deploy a test environment using Fun Deploy and then make mock calls via Fun Invoke or send them directly via CURL
This example implements only unit tests, integration tests and E2E tests trigger in a similar way to the Travis example, and the implementation can be configured by referring to the method tips above.
Unit testing
Unit tests of FC functions are no different from normal functions. Use a familiar unit testing framework, which in this case uses JEST. Let’s look at a test case snippet
jest.mock('moment-timezone');
const { tz } = require('moment-timezone');
const { handler } = require('./index');
const EXPECTED_DATE = '2018-10-01 00:00:00';
const TIMEZONE = 'America/New_York';
describe('when call handle', () => {
it('Should return the expected date if the provied timezone exists', () = > {const mockReq = {
queries: {
tz: TIMEZONE
}
}
const mockResp = {
setHeader: jest.fn(),
send: jest.fn()
}
tz.names = (a)= > [TIMEZONE];
tz.mockImplementation((a)= > {
return {
format: (a)= > EXPECTED_DATE
}
})
handler(mockReq, mockResp, null);
expect(mockResp.setHeader.mock.calls.length).toBe(1);
expect(mockResp.setHeader.mock.calls[0] [0]).toBe('content-type');
expect(mockResp.setHeader.mock.calls[0] [1]).toBe('application/json');
expect(mockResp.send.mock.calls.length).toBe(1);
expect(mockResp.send.mock.calls[0] [0]).toBe(JSON.stringify({
statusCode: '200'.message: `The time in ${TIMEZONE} is: ${EXPECTED_DATE}`
}, null.' '));
});
});
Copy the code
Mock the moment-timezone with jest. Mock so that tz returns a predefined value when called instead of a dynamically changing time.
Typically, this type of unit test is divided into three steps:
- Mock dependent values or parameters
- Calling the test function
- An assertion returns the result and the argument to be called
If there are no native dependencies (dependencies on Linux executables or so libraries), use NPM test to trigger the test. If there are native dependencies, run the following command in fun’s sbox simulation to trigger the test
fun install sbox -f tz-time --cmd 'npm install'
Copy the code
Integration testing
The integration test in this example starts the function locally with the fun local start command. Since the function is configured with an HTTP trigger, the function can be invoked via an HTTP request.
Integration tests are still written in the Jest framework. To distinguish the integration test file from the unit test file *.test.js, the integration test file uses the.integration-test.js file suffix. To make jest command run independent integration test cases rather than and mixed together, the unit test to compile the following file jest. Config. Integration. Js
module.exports = {
testMatch: ["* * /? (*) integration-test.js"]};Copy the code
Then configure scripts in package.json
"scripts": {
"integration:test": "jest -c jest.config.integration.js"
}
Copy the code
You can then perform integration tests by executing NPM Run Integration :test.
Then add the integration-test target to the Makefile based on this:
funlocal.PID:fun local start & echo ? ! >$@
integration-test: funlocal.PID
bin/waitForServer.sh http://localhost:8000/2016-08-15/proxy/tz-time/tz-time/
npm run integration:test
kill -2 `cat $<` && rm $<
Copy the code
The integration-test target relies on the funlocal.PID target, which is responsible for starting a Fun Local process that starts port 8000 locally. Read the Makefile code above
fun local start & echo ? ! > $@
Start the fun Local process and write the process PID to the target file of the same name funlocal.pidbin/waitForServer.sh http://localhost:8000/2016-08-15/proxy/tz-time/tz-time/
Test whether the Fun Local process has started with a URL.kill -2 `cat $<` && rm $<
Destroy the Fun Local process after the test is complete.
NPM Run Integration :test launches several test cases, one of which is shown in the following example:
const request = require('request');
const url = 'http://localhost:8000/2016-08-15/proxy/tz-time/tz-time/';
describe('request url', () => {
it('without tz', (done) => {
request(url, (error, response, data) => {
if (error) {
fail(error);
} else {
const resData = JSON.parse(data);
expect(resData.statusCode).toBe(200);
expect(resData.message).toContain('Asia/Shanghai');
}
done();
});
});
});
Copy the code
End-to-end testing
The test cases for end-to-end testing and integration testing are very similar, but the difference lies in the server side of testing, where end-to-end testing deploys a real environment and integration testing is locally simulated by Fun Local.
In this example, use fun deploy-use-ros to deploy an environment named TZ-e2e – with a timestamp, so that each test deploys a new environment without affecting each other. After the test is complete, delete the ROS stack using aliyun-CLI tool.
The following Makefile target is tested end-to-end:
stack_name := tz-e2e-$(shell date +%s)
e2e-test:
# deploy e2e
bin/deployE2EStack.sh $(stack_name)
# run test
npm run e2e:test
# cleanup
bin/delRosStack.sh $(stack_name)
Copy the code
bin/deployE2EStack.sh $(stack_name)
Responsible for deploying a new ROS Stack. You need to build the deliverables using the Fun Package before deploying, and refer to the next section for details on how to build the deliverables.npm run e2e:test
Run end-to-end testsbin/delRosStack.sh $(stack_name)
After the test is complete, cleaning up the deployed ROS Stack frees up responding cloud resources.
Build deliverables
The fun package command can be used to build the deliverables, and the Fun package needs to specify an OSS bucket. The fun package command completes the following steps:
- Package the code compilation into a Zip file.
- Upload the code package to the OSS bucket.
- Generate a new file, template.packaged. Yml, with the code local address changed to the OSS bucket address.
The generated template.packaged. Yml file is the final deliverable and can be deployed with the Fun Deploy name.
Continuous deployment
Once the build has produced the deliverables, it can be deployed with Fun Deploy. Continuous deployment needs to address two issues:
- New deployment and upgrade deployment are supported
- One set of resource descriptions supports the deployment of multiple sets, such as test, staging, and Production environments.
Fun Deploy can easily solve these problems with ROS.
fun deploy --use-ros --stack-name tz-staging --assume-yes
Copy the code
Among them:
--use-ros
Represents deployment with ROS, which works by pushing template.yml to the ROS service, which creates and updates each service. Without this parameter, Fun parses template.yml locally, calling the API for resource creation. ROS has the added benefit of being able to roll back deployment, automatically in the event of a failure.--stack-name
Specify the name of a stack, a ROS concept that can be understood as a set of environments.--assume-yes
Used in unattended mode, skip the confirmation prompt.
Note that if the –use-ros parameter is not specified, fun Deploy will be deployed directly by calling the cloud resource API. This is the default deployment mode of Fun Deploy, although idempotent deployment is also implemented. However, only limited cloud resources (FC, OTS, API Gateway, etc.) can be deployed, which is far less abundant than ROS, and ROS does not support rollback and one-click delete. Therefore, it is not recommended here.
summary
For the scripted configuration of all the above steps, refer to the Makefile and.travis. Yml files. Github and Travis CI can be linked through the above two files to achieve CI/CD triggered by code submission.
This article describes FC functions
- How do you test, especially the automation of unit tests
- How do I build the deliverables by uploading the code file to the OSS Bucket via fun Package and having the deliverables program a text description file template.packaged. Yml
- How to continuously deploy, using ROS to deploy multiple environments and update the same environment multiple times.
Refer to the reading
- Source code example project TZ-time
- Develop proper posture for function computations – use ROS for resource orchestration
- Funcraft
- Aliyun Serverless VSCode Extension
“Alibaba Cloud originators pay close attention to technical fields such as microservice, Serverless, container and Service Mesh, focus on cloud native popular technology trends and large-scale implementation of cloud native, and become the technical circle that knows most about cloud native developers.”