Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test(analyses snapshots): partial tip protocols #15916

Closed
wants to merge 16 commits into from
23 changes: 23 additions & 0 deletions analyses-snapshot-testing/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,26 @@ build-opentrons-analysis:
.PHONY: generate-protocols
generate-protocols:
python -m pipenv run python -m automation.data.protocol_registry


OPENTRONS_VERSION ?= edge
export OPENTRONS_VERSION

.PHONY: build-rs
build-rs:
@echo "Building docker image for opentrons-robot-server:$(OPENTRONS_VERSION)"
@echo "Cache is always busted to ensure latest version of the code is used"
@echo "If you want to build a different version, run 'make build-rs OPENTRONS_VERSION=chore_release-8.0.0'"
docker build --build-arg OPENTRONS_VERSION=$(OPENTRONS_VERSION) --build-arg CACHEBUST=$(CACHEBUST) -t opentrons-robot-server:$(OPENTRONS_VERSION) -f citools/Dockerfile.server .

.PHONY: run-flex
run-flex:
@echo "Running opentrons-robot-server:$(OPENTRONS_VERSION)"
@echo "If you want to run a different version, run 'make run-flex OPENTRONS_VERSION=chore_release-8.0.0'"
docker run -p 31950:31950 --env-file ../robot-server/dev-flex.env opentrons-robot-server:$(OPENTRONS_VERSION)

.PHONY: run-ot2
run-ot2:
@echo "Running opentrons-robot-server:$(OPENTRONS_VERSION)"
@echo "If you want to run a different version, run 'make run-ot2 OPENTRONS_VERSION=chore_release-8.0.0'"
docker run -p 31950:31950 --env-file ../robot-server/dev.env opentrons-robot-server:$(OPENTRONS_VERSION)
20 changes: 20 additions & 0 deletions analyses-snapshot-testing/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@
- In CI this is the `SNAPSHOT_REF`. This is the branch or tag of the test code/snapshots that analyses generated will be compared to.
- The `ANALYSIS_REF` is the branch or tag that you want analyses generated from.

## Build the opentrons-analysis image

> This ALWAYS gets the remote code pushed to Opentrons/opentrons for the specified ANALYSIS_REF

`make build-opentrons-analysis ANALYSIS_REF=chore_release-8.0.0`

## Running the tests locally

- Compare the current branch snapshots to analyses generated from the edge branch
Expand All @@ -38,3 +44,17 @@
- `make snapshot-test PROTOCOL_NAMES=Flex_S_v2_19_Illumina_DNA_PCR_Free OVERRIDE_PROTOCOL_NAMES=none`
- `make snapshot-test PROTOCOL_NAMES=none OVERRIDE_PROTOCOL_NAMES=Flex_X_v2_18_NO_PIPETTES_Overrides_BadTypesInRTP`
- `make snapshot-test PROTOCOL_NAMES="Flex_S_v2_19_Illumina_DNA_PCR_Free,OT2_S_v2_18_P300M_P20S_HS_TC_TM_SmokeTestV3" OVERRIDE_PROTOCOL_NAMES=none`

## Running a Flex just like `make -C robot-server dev-flex`

> This ALWAYS gets the remote code pushed to Opentrons/opentrons for the specified OPENTRONS_VERSION

```shell
cd analyses-snapshot-testing \
&& make build-rs OPENTRONS_VERSION=chore_release-8.0.0 \
&& make run-rs OPENTRONS_VERSION=chore_release-8.0.0`
```

### Default OPENTRONS_VERSION=edge in the Makefile so you can omit it if you want latest edge

`cd analyses-snapshot-testing && make build-rs && make run-rs`
81 changes: 81 additions & 0 deletions analyses-snapshot-testing/automation/data/protocols.py
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,74 @@ class Protocols:
robot="Flex",
)

# analyses-snapshot-testing/files/protocols/Flex_S_v2_20_8_None_PARTIAL_COLUMN_HappyPath.py
Flex_S_v2_20_8_None_PARTIAL_COLUMN_HappyPath: Protocol = Protocol(
file_stem="Flex_S_v2_20_8_None_PARTIAL_COLUMN_HappyPath",
file_extension="py",
robot="Flex",
)
# analyses-snapshot-testing/files/protocols/Flex_S_v2_20_8_None_SINGLE_HappyPath.py
Flex_S_v2_20_8_None_SINGLE_HappyPath: Protocol = Protocol(
file_stem="Flex_S_v2_20_8_None_SINGLE_HappyPath",
file_extension="py",
robot="Flex",
)
# analyses-snapshot-testing/files/protocols/Flex_S_v2_20_96_AllCorners.py
Flex_S_v2_20_96_AllCorners: Protocol = Protocol(
file_stem="Flex_S_v2_20_96_AllCorners",
file_extension="py",
robot="Flex",
)
# analyses-snapshot-testing/files/protocols/Flex_S_v2_20_96_None_COLUMN_HappyPath.py
Flex_S_v2_20_96_None_COLUMN_HappyPath: Protocol = Protocol(
file_stem="Flex_S_v2_20_96_None_COLUMN_HappyPath",
file_extension="py",
robot="Flex",
)
# analyses-snapshot-testing/files/protocols/Flex_S_v2_20_96_None_Column3_SINGLE_.py
Flex_S_v2_20_96_None_Column3_SINGLE_: Protocol = Protocol(
file_stem="Flex_S_v2_20_96_None_Column3_SINGLE_",
file_extension="py",
robot="Flex",
)
# analyses-snapshot-testing/files/protocols/Flex_S_v2_20_96_None_ROW_HappyPath.py
Flex_S_v2_20_96_None_ROW_HappyPath: Protocol = Protocol(
file_stem="Flex_S_v2_20_96_None_ROW_HappyPath",
file_extension="py",
robot="Flex",
)
# analyses-snapshot-testing/files/protocols/Flex_S_v2_20_96_None_SINGLE_4Corners50ul.py
Flex_S_v2_20_96_None_SINGLE_4Corners50ul: Protocol = Protocol(
file_stem="Flex_S_v2_20_96_None_SINGLE_4Corners50ul",
file_extension="py",
robot="Flex",
)
# analyses-snapshot-testing/files/protocols/Flex_S_v2_20_96_None_SINGLE_HappyPathNorthSide.py
Flex_S_v2_20_96_None_SINGLE_HappyPathNorthSide: Protocol = Protocol(
file_stem="Flex_S_v2_20_96_None_SINGLE_HappyPathNorthSide",
file_extension="py",
robot="Flex",
)
# analyses-snapshot-testing/files/protocols/Flex_S_v2_20_96_None_SINGLE_HappyPathSouthSide.py
Flex_S_v2_20_96_None_SINGLE_HappyPathSouthSide: Protocol = Protocol(
file_stem="Flex_S_v2_20_96_None_SINGLE_HappyPathSouthSide",
file_extension="py",
robot="Flex",
)

# analyses-snapshot-testing/files/protocols/Flex_S_v2_20_P8X1000_P50_LLD.py
Flex_S_v2_20_P8X1000_P50_LLD: Protocol = Protocol(
file_stem="Flex_S_v2_20_P8X1000_P50_LLD",
file_extension="py",
robot="Flex",
)
# analyses-snapshot-testing/files/protocols/Flex_S_v2_20_P50_LPD.py
Flex_S_v2_20_P50_LPD: Protocol = Protocol(
file_stem="Flex_S_v2_20_P50_LPD",
file_extension="py",
robot="Flex",
)

OT2_X_v2_18_None_None_duplicateRTPVariableName: Protocol = Protocol(
file_stem="OT2_X_v2_18_None_None_duplicateRTPVariableName",
file_extension="py",
Expand Down Expand Up @@ -677,6 +745,19 @@ class Protocols:
robot="OT2",
)

# analyses-snapshot-testing/files/protocols/OT2_S_v2_20_8_None_PARTIAL_COLUMN_HappyPathMixedTipRacks.py
OT2_S_v2_20_8_None_PARTIAL_COLUMN_HappyPathMixedTipRacks: Protocol = Protocol(
file_stem="OT2_S_v2_20_8_None_PARTIAL_COLUMN_HappyPathMixedTipRacks",
file_extension="py",
robot="OT2",
)
# analyses-snapshot-testing/files/protocols/OT2_S_v2_20_8_None_SINGLE_HappyPath.py
OT2_S_v2_20_8_None_SINGLE_HappyPath: Protocol = Protocol(
file_stem="OT2_S_v2_20_8_None_SINGLE_HappyPath",
file_extension="py",
robot="OT2",
)

##########################################################################################################
# Begin Protocol Library Protocols #######################################################################
##########################################################################################################
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,72 @@ class ProtocolsWithOverrides:
override_variable_name="type_to_test",
overrides=["str_default_no_matching_choices", "float_default_no_matching_choices", "int_default_no_matching_choices"],
)

# analyses-snapshot-testing/files/protocols/Flex_X_v2_20_96_and_8_Overrides_InvalidConfigs.py

Flex_X_v2_20_96_and_8_Overrides_InvalidConfigs: ProtocolWithOverrides = ProtocolWithOverrides(
file_stem="Flex_X_v2_20_96_and_8_Overrides_InvalidConfigs",
file_extension="py",
robot="Flex",
override_variable_name="key",
overrides=[
"ninety_six_partial_column_1",
"ninety_six_partial_column_2",
"ninety_six_partial_column_3",
"eight_partial_column_bottom_left",
"eight_partial_column_bottom_right",
"eight_partial_column_no_end",
"return_tip_error",
"drop_tip_with_location",
],
)

# analyses-snapshot-testing/files/protocols/Flex_X_v2_20_96_None_Overrides_TooTallLabware.py

Flex_X_v2_20_96_None_Overrides_TooTallLabware: ProtocolWithOverrides = ProtocolWithOverrides(
file_stem="Flex_X_v2_20_96_None_Overrides_TooTallLabware",
file_extension="py",
robot="Flex",
override_variable_name="key",
overrides=[
"transfer_source_collision",
"transfer_destination_collision",
"c3_right_edge",
"north",
"north_west",
"west",
"south_west",
"south",
"south_east",
"east",
"east_column",
"west_column",
"north_row",
"south_row",
"top_edge",
"bottom_left_edge",
"bottom_left_edge",
"bottom_right_edge",
"mix_collision",
"consolidate_source_collision",
"consolidate_destination_collision",
"distribute_source_collision",
"distribute_destination_collision",
],
)

# analyses-snapshot-testing/files/protocols/OT2_X_v2_20_8_Overrides_InvalidConfigs.py

OT2_X_v2_20_8_Overrides_InvalidConfigs: ProtocolWithOverrides = ProtocolWithOverrides(
file_stem="OT2_X_v2_20_8_Overrides_InvalidConfigs",
file_extension="py",
robot="Flex",
override_variable_name="key",
overrides=[
"eight_partial_column_bottom_left",
"eight_partial_column_bottom_right",
"eight_partial_column_no_end",
"return_tip_error",
"drop_tip_with_location",
],
)
31 changes: 31 additions & 0 deletions analyses-snapshot-testing/citools/Dockerfile.server
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Use Python 3.10 as the base image
FROM python:3.10-slim-bullseye

# Update packages and install dependencies
RUN apt-get update && \
apt-get upgrade -y && \
apt-get install -y git libsystemd-dev build-essential pkg-config network-manager

# Define build arguments
ARG OPENTRONS_VERSION=edge

# Set the working directory
WORKDIR /opentrons

# Clone the Opentrons repository
ARG CACHEBUST=1
RUN git clone --branch $OPENTRONS_VERSION --depth 1 https://github.com/Opentrons/opentrons .

# Install dependencies
RUN make setup-py -j

WORKDIR /opentrons/robot-server

# Set the port via environment variable
ENV PORT=31950

# Expose the port
EXPOSE ${PORT}

# Default command
CMD ["sh", "-c", "python -m pipenv run uvicorn robot_server.app:app --host 0.0.0.0 --port ${PORT} --ws wsproto --lifespan on"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
from opentrons.protocol_api import PARTIAL_COLUMN

metadata = {
"protocolName": "flex_8channel_1000 Simple",
"description": "A protocol that demonstrates safe actions with flex_8channel_1000",
"author": "Josh McVey",
}

requirements = {
"robotType": "Flex",
"apiLevel": "2.20",
}


def comment_tip_rack_status(ctx, tip_rack):
"""
Print out the tip status for each row in a tip rack.
Each row (A-H) will print the well statuses for columns 1-12 in a single comment,
with a '🟢' for present tips and a '❌' for missing tips.
"""
range_A_to_H = [chr(i) for i in range(ord("A"), ord("H") + 1)]
range_1_to_12 = range(1, 13)

ctx.comment(f"Tip rack in {tip_rack.parent}")

for row in range_A_to_H:
status_line = f"{row}: "
for col in range_1_to_12:
well = f"{row}{col}"
has_tip = tip_rack.wells_by_name()[well].has_tip
status_emoji = "🟢" if has_tip else "❌"
status_line += f"{well} {status_emoji} "

# Print the full status line for the row
ctx.comment(status_line)


def run(protocol):

trash = protocol.load_trash_bin("A3") # must load trash bin
tip_rack = protocol.load_labware(
load_name="opentrons_flex_96_tiprack_1000ul",
label="Tip Rack",
location="A1",
)

pipette = protocol.load_instrument(instrument_name="flex_8channel_1000", mount="left", tip_racks=[tip_rack])

source_labware_C2 = protocol.load_labware(
load_name="nest_1_reservoir_290ml",
label="Source Reservoir",
location="C2",
)

destination_labware_D2 = protocol.load_labware(
load_name="nest_96_wellplate_100ul_pcr_full_skirt",
label="PCR Plate",
location="2",
)

volume = 100
pipette.pick_up_tip()
comment_tip_rack_status(protocol, tip_rack)
pipette.aspirate(volume=volume, location=destination_labware_D2["H1"])
pipette.dispense(volume=volume, location=destination_labware_D2["H2"])
for i in range(1, 13):
protocol.comment(f"Touching tip to {destination_labware_D2[f'H{i}']}")
pipette.touch_tip(location=destination_labware_D2[f"H{i}"])

pipette.blow_out(location=destination_labware_D2["H1"])
pipette.mix(repetitions=3, volume=volume, location=destination_labware_D2["H1"])
pipette.drop_tip()

range_A_to_H = [chr(i) for i in range(ord("A"), ord("H") + 1)]
column1 = [destination_labware_D2[f"{row}1"] for row in range_A_to_H]
column2 = [destination_labware_D2[f"{row}2"] for row in range_A_to_H]
column3 = [destination_labware_D2[f"{row}3"] for row in range_A_to_H]
column4 = [destination_labware_D2[f"{row}4"] for row in range_A_to_H]
column5 = [destination_labware_D2[f"{row}5"] for row in range_A_to_H]
column6 = [destination_labware_D2[f"{row}6"] for row in range_A_to_H]
column7 = [destination_labware_D2[f"{row}7"] for row in range_A_to_H]

protocol.comment(f"Transferring {volume}uL from column 1 to column 2")
pipette.transfer(volume=volume, source=column1, dest=column2)
comment_tip_rack_status(protocol, tip_rack)

volume = 50
protocol.comment(f"Distribute {volume}uL from column 2 to column 3 and 4")
pipette.distribute(volume=volume, source=column2, dest=column3 + column4)
comment_tip_rack_status(protocol, tip_rack)
protocol.comment(f"Consolidate {volume}uL from column 5 and 6 to column 7")
pipette.consolidate(volume=volume, source=column5 + column6, dest=column7)
comment_tip_rack_status(protocol, tip_rack)
Loading
Loading